From 869da3eababb833eb62c804ee2f78c639b67be4b Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 16 Oct 2014 14:07:29 -0700 Subject: Fixing some IconCache methods not thread safe Bug: 17981568 Change-Id: I0d49604c2e38bc9017cba527d87e24e8b086f1da --- src/com/android/launcher3/IconCache.java | 172 ++++++++------------- src/com/android/launcher3/WidgetPreviewLoader.java | 2 +- 2 files changed, 68 insertions(+), 106 deletions(-) diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 72b6d8951..823ac2299 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -24,7 +24,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -118,8 +117,7 @@ public class IconCache { } public Drawable getFullResDefaultActivityIcon() { - return getFullResIcon(Resources.getSystem(), - android.R.mipmap.sym_def_app_icon); + return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon); } private Drawable getFullResIcon(Resources resources, int iconId) { @@ -152,10 +150,6 @@ public class IconCache { return mIconDpi; } - public Drawable getFullResIcon(ResolveInfo info) { - return getFullResIcon(info.activityInfo); - } - public Drawable getFullResIcon(ActivityInfo info) { Resources resources; @@ -192,15 +186,13 @@ public class IconCache { * Remove any records for the supplied ComponentName. */ public void remove(ComponentName componentName, UserHandleCompat user) { - synchronized (mCache) { - mCache.remove(new CacheKey(componentName, user)); - } + mCache.remove(new CacheKey(componentName, user)); } /** * Remove any records for the supplied package name. */ - public void remove(String packageName, UserHandleCompat user) { + public synchronized void remove(String packageName, UserHandleCompat user) { HashSet forDeletion = new HashSet(); for (CacheKey key: mCache.keySet()) { if (key.componentName.getPackageName().equals(packageName) @@ -216,24 +208,20 @@ public class IconCache { /** * Empty out the cache. */ - public void flush() { - synchronized (mCache) { - mCache.clear(); - } + public synchronized void flush() { + mCache.clear(); } /** * Empty out the cache that aren't of the correct grid size */ - public void flushInvalidIcons(DeviceProfile grid) { - synchronized (mCache) { - Iterator> it = mCache.entrySet().iterator(); - while (it.hasNext()) { - final CacheEntry e = it.next().getValue(); - if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx - || e.icon.getHeight() < grid.iconSizePx)) { - it.remove(); - } + public synchronized void flushInvalidIcons(DeviceProfile grid) { + Iterator> it = mCache.entrySet().iterator(); + while (it.hasNext()) { + final CacheEntry e = it.next().getValue(); + if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx + || e.icon.getHeight() < grid.iconSizePx)) { + it.remove(); } } } @@ -241,91 +229,78 @@ public class IconCache { /** * Fill in "application" with the icon and label for "info." */ - public void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info, + public synchronized void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info, HashMap labelCache) { - synchronized (mCache) { - CacheEntry entry = cacheLocked(application.componentName, info, labelCache, - info.getUser(), false, application.unreadNum); - - application.title = entry.title; - application.iconBitmap = entry.icon; - application.contentDescription = entry.contentDescription; - } - } + CacheEntry entry = cacheLocked(application.componentName, info, labelCache, + info.getUser(), false, application.unreadNum); - public Bitmap getIcon(Intent intent, UserHandleCompat user) { - return getIcon(intent, null, user, true); + application.title = entry.title; + application.iconBitmap = entry.icon; + application.contentDescription = entry.contentDescription; } - private Bitmap getIcon(Intent intent, String title, UserHandleCompat user, boolean usePkgIcon) { - synchronized (mCache) { - ComponentName component = intent.getComponent(); - // null info means not installed, but if we have a component from the intent then - // we should still look in the cache for restored app icons. - if (component == null) { - return getDefaultIcon(user); - } - - LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); - CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon, -1); - if (title != null) { - entry.title = title; - entry.contentDescription = mUserManager.getBadgedLabelForUser(title, user); - } - return entry.icon; + public synchronized Bitmap getIcon(Intent intent, UserHandleCompat user) { + ComponentName component = intent.getComponent(); + // null info means not installed, but if we have a component from the intent then + // we should still look in the cache for restored app icons. + if (component == null) { + return getDefaultIcon(user); } + + LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, true, -1); + return entry.icon; } /** * Fill in "shortcutInfo" with the icon and label for "info." */ - public void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent, UserHandleCompat user, - boolean usePkgIcon) { - synchronized (mCache) { - ComponentName component = intent.getComponent(); - // null info means not installed, but if we have a component from the intent then - // we should still look in the cache for restored app icons. - if (component == null) { - shortcutInfo.setIcon(getDefaultIcon(user)); - shortcutInfo.title = ""; - shortcutInfo.usingFallbackIcon = true; - } else { - LauncherActivityInfoCompat launcherActInfo = - mLauncherApps.resolveActivity(intent, user); - CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon, - -1); - - shortcutInfo.setIcon(entry.icon); - shortcutInfo.title = entry.title; - shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user); - } + public synchronized void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent, + UserHandleCompat user, boolean usePkgIcon) { + ComponentName component = intent.getComponent(); + // null info means not installed, but if we have a component from the intent then + // we should still look in the cache for restored app icons. + if (component == null) { + shortcutInfo.setIcon(getDefaultIcon(user)); + shortcutInfo.title = ""; + shortcutInfo.usingFallbackIcon = true; + } else { + LauncherActivityInfoCompat launcherActInfo = + mLauncherApps.resolveActivity(intent, user); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon, -1); + shortcutInfo.setIcon(entry.icon); + shortcutInfo.title = entry.title; + shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user); } } - public Bitmap getDefaultIcon(UserHandleCompat user) { + public synchronized Bitmap getDefaultIcon(UserHandleCompat user) { if (!mDefaultIcons.containsKey(user)) { mDefaultIcons.put(user, makeDefaultIcon(user)); } return mDefaultIcons.get(user); } - public Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info, - HashMap labelCache) { - synchronized (mCache) { - if (info == null || component == null) { - return null; - } + public synchronized Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info, + HashMap labelCache) { - CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false, -1); - return entry.icon; + if (info == null || component == null) { + return null; } + + CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false, -1); + return entry.icon; } public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) { return mDefaultIcons.get(user) == icon; } + /** + * Retrieves the entry from the cache. If the entry is not present, it creates a new entry. + * This method is not thread safe, it must be called from a synchronized method. + */ private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info, HashMap labelCache, UserHandleCompat user, boolean usePackageIcon, int unreadNum) { @@ -426,7 +401,7 @@ public class IconCache { * Gets an entry for the package, which can be used as a fallback entry for various components. */ private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) { - ComponentName cn = getPackageComponent(packageName); + ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME); CacheKey cacheKey = new CacheKey(cn, user); CacheEntry entry = mCache.get(cacheKey); if (entry == null) { @@ -449,15 +424,13 @@ public class IconCache { return entry; } - public HashMap getAllIcons() { - synchronized (mCache) { - HashMap set = new HashMap(); - for (CacheKey ck : mCache.keySet()) { - final CacheEntry e = mCache.get(ck); - set.put(ck.componentName, e.icon); - } - return set; + public synchronized HashMap getAllIcons() { + HashMap set = new HashMap(); + for (CacheKey ck : mCache.keySet()) { + final CacheEntry e = mCache.get(ck); + set.put(ck.componentName, e.icon); } + return set; } /** @@ -563,23 +536,16 @@ public class IconCache { * Remove a pre-loaded icon from the persistent icon cache. * * @param componentName the component that should own the icon - * @returns true on success */ - public boolean deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) { + public void deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) { // We don't keep icons for other profiles in persistent cache. - if (!user.equals(UserHandleCompat.myUserHandle())) { - return false; - } - if (componentName == null) { - return false; - } - if (mCache.remove(componentName) != null) { - if (DEBUG) Log.d(TAG, "removed pre-loaded icon from the in-memory cache"); + if (!user.equals(UserHandleCompat.myUserHandle()) || componentName == null) { + return; } + remove(componentName, user); boolean success = mContext.deleteFile(getResourceFilename(componentName)); if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache"); - return success; } private static String getResourceFilename(ComponentName component) { @@ -587,8 +553,4 @@ public class IconCache { String filename = resourceName.replace(File.separatorChar, '_'); return RESOURCE_FILE_PREFIX + filename; } - - static ComponentName getPackageComponent(String packageName) { - return new ComponentName(packageName, EMPTY_CLASS_NAME); - } } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index a5e9f1dc7..7b803cdc1 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -644,7 +644,7 @@ public class WidgetPreviewLoader { c.setBitmap(null); } // Render the icon - Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info)); + Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo)); int paddingTop = mContext. getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); -- cgit v1.2.3