From d427cbd33206cbcc88ac4a0f0c29ef831d4bb5b5 Mon Sep 17 00:00:00 2001 From: judds Date: Mon, 11 Dec 2017 12:00:05 -0800 Subject: [PATCH] Fix a race causing an NPE when obtaining load paths for resources. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=178651500 --- .../java/com/bumptech/glide/Registry.java | 6 ++- .../glide/provider/LoadPathCache.java | 48 ++++++++++++++----- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/library/src/main/java/com/bumptech/glide/Registry.java b/library/src/main/java/com/bumptech/glide/Registry.java index c2d589552b..d531f09713 100644 --- a/library/src/main/java/com/bumptech/glide/Registry.java +++ b/library/src/main/java/com/bumptech/glide/Registry.java @@ -1,5 +1,6 @@ package com.bumptech.glide; +import android.support.annotation.Nullable; import android.support.v4.util.Pools.Pool; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ImageHeaderParser; @@ -446,11 +447,14 @@ public Registry replace( return this; } + @Nullable public LoadPath getLoadPath( Class dataClass, Class resourceClass, Class transcodeClass) { LoadPath result = loadPathCache.get(dataClass, resourceClass, transcodeClass); - if (result == null && !loadPathCache.contains(dataClass, resourceClass, transcodeClass)) { + if (loadPathCache.isEmptyLoadPath(result)) { + return null; + } else if (result == null) { List> decodePaths = getDecodePaths(dataClass, resourceClass, transcodeClass); // It's possible there is no way to decode or transcode to the desired types from a given diff --git a/library/src/main/java/com/bumptech/glide/provider/LoadPathCache.java b/library/src/main/java/com/bumptech/glide/provider/LoadPathCache.java index 6cc5d96301..d4b24a8919 100644 --- a/library/src/main/java/com/bumptech/glide/provider/LoadPathCache.java +++ b/library/src/main/java/com/bumptech/glide/provider/LoadPathCache.java @@ -2,8 +2,11 @@ import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; +import com.bumptech.glide.load.engine.DecodePath; import com.bumptech.glide.load.engine.LoadPath; +import com.bumptech.glide.load.resource.transcode.UnitTranscoder; import com.bumptech.glide.util.MultiClassKey; +import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; /** @@ -11,19 +14,38 @@ * {@link com.bumptech.glide.load.engine.LoadPath}s capable of decoding with the requested types. */ public class LoadPathCache { + private static final LoadPath NO_PATHS_SIGNAL = + new LoadPath<>( + Object.class, + Object.class, + Object.class, + Collections.singletonList( + new DecodePath<>( + Object.class, + Object.class, + Object.class, + Collections.emptyList(), + new UnitTranscoder<>(), + /*listPool=*/ null)), + /*listPool=*/ null); + private final ArrayMap> cache = new ArrayMap<>(); private final AtomicReference keyRef = new AtomicReference<>(); - public boolean contains(Class dataClass, Class resourceClass, Class transcodeClass) { - MultiClassKey key = getKey(dataClass, resourceClass, transcodeClass); - boolean result; - synchronized (cache) { - result = cache.containsKey(key); - } - keyRef.set(key); - return result; + /** + * Returns {@code} true if the given {@link LoadPath} is the signal object returned from + * {@link #get(Class, Class, Class)} that indicates that we've previously found that there are + * no available paths to load the requested resources and {@code false} otherwise. + */ + public boolean isEmptyLoadPath(@Nullable LoadPath path) { + return NO_PATHS_SIGNAL.equals(path); } + /** + * May return {@link #NO_PATHS_SIGNAL} to indicate that we've previously found that there are 0 + * available load paths for the requested types. Callers must check using + * {@link #isEmptyLoadPath(LoadPath)} before using any load path returned by this method. + */ @SuppressWarnings("unchecked") @Nullable public LoadPath get( @@ -38,10 +60,14 @@ public LoadPath get( return (LoadPath) result; } - public void put(Class dataClass, Class resourceClass, Class transcodeClass, - LoadPath loadPath) { + public void put( + Class dataClass, Class resourceClass, + Class transcodeClass, + @Nullable LoadPath loadPath) { synchronized (cache) { - cache.put(new MultiClassKey(dataClass, resourceClass, transcodeClass), loadPath); + cache.put( + new MultiClassKey(dataClass, resourceClass, transcodeClass), + loadPath != null ? loadPath : NO_PATHS_SIGNAL); } }