Skip to content

Commit 5cccdfb

Browse files
sjuddglide-copybara-robot
authored andcommittedAug 13, 2019
Make sure EngineJob uses the Request's shared lock.
PiperOrigin-RevId: 263201451
1 parent 0ff4f46 commit 5cccdfb

File tree

4 files changed

+40
-16
lines changed

4 files changed

+40
-16
lines changed
 

‎library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -383,16 +383,20 @@ public StateVerifier getVerifier() {
383383
private class CallLoadFailed implements Runnable {
384384

385385
private final ResourceCallback cb;
386+
private final Object lock;
386387

387388
CallLoadFailed(ResourceCallback cb) {
388389
this.cb = cb;
390+
// The lock may be reset if the callback is removed while our Runnable is pending, so memoize
391+
// it here. We're assuming that the lock is never re-used.
392+
this.lock = Preconditions.checkNotNull(cb.getLock());
389393
}
390394

391395
@Override
392396
public void run() {
393397
// Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
394398
// (b/136032534).
395-
synchronized (cb) {
399+
synchronized (lock) {
396400
synchronized (EngineJob.this) {
397401
if (cbs.contains(cb)) {
398402
callCallbackOnLoadFailed(cb);
@@ -407,16 +411,20 @@ public void run() {
407411
private class CallResourceReady implements Runnable {
408412

409413
private final ResourceCallback cb;
414+
private final Object lock;
410415

411416
CallResourceReady(ResourceCallback cb) {
412417
this.cb = cb;
418+
// The lock may be reset if the callback is removed while our Runnable is pending, so memoize
419+
// it here. We're assuming that the lock is never re-used.
420+
this.lock = Preconditions.checkNotNull(cb.getLock());
413421
}
414422

415423
@Override
416424
public void run() {
417425
// Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
418426
// (b/136032534).
419-
synchronized (cb) {
427+
synchronized (lock) {
420428
synchronized (EngineJob.this) {
421429
if (cbs.contains(cb)) {
422430
// Acquire for this particular callback.

‎library/src/main/java/com/bumptech/glide/request/ResourceCallback.java

+3
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ public interface ResourceCallback {
2323
* @param e a non-null {@link GlideException}.
2424
*/
2525
void onLoadFailed(GlideException e);
26+
27+
/** Returns the lock to use when notifying individual requests. */
28+
Object getLock();
2629
}

‎library/src/main/java/com/bumptech/glide/request/SingleRequest.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.bumptech.glide.request.transition.Transition;
2222
import com.bumptech.glide.request.transition.TransitionFactory;
2323
import com.bumptech.glide.util.LogTime;
24+
import com.bumptech.glide.util.Preconditions;
2425
import com.bumptech.glide.util.Synthetic;
2526
import com.bumptech.glide.util.Util;
2627
import com.bumptech.glide.util.pool.FactoryPools;
@@ -229,7 +230,7 @@ private void init(
229230
Engine engine,
230231
TransitionFactory<? super R> animationFactory,
231232
Executor callbackExecutor) {
232-
this.requestLock = requestLock;
233+
this.requestLock = Preconditions.checkNotNull(requestLock);
233234
synchronized (this.requestLock) {
234235
this.context = context;
235236
this.glideContext = glideContext;
@@ -716,6 +717,12 @@ public void onLoadFailed(GlideException e) {
716717
onLoadFailed(e, Log.WARN);
717718
}
718719

720+
@Override
721+
public Object getLock() {
722+
stateVerifier.throwIfRecycled();
723+
return requestLock;
724+
}
725+
719726
private void onLoadFailed(GlideException e, int maxLogLevel) {
720727
stateVerifier.throwIfRecycled();
721728
synchronized (requestLock) {

‎library/test/src/test/java/com/bumptech/glide/load/engine/EngineJobTest.java

+19-13
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ public void testRemovingAllCallbacksCancelsRunner() {
188188
@Test
189189
public void removingSomeCallbacksDoesNotCancelRunner() {
190190
EngineJob<Object> job = harness.getJob();
191-
job.addCallback(mock(ResourceCallback.class), Executors.directExecutor());
191+
job.addCallback(mockResourceCallback(), Executors.directExecutor());
192192
job.removeCallback(harness.cb);
193193

194194
assertFalse(job.isCancelled());
@@ -261,8 +261,8 @@ public void testDoesNotAcquireOnceForMemoryCacheIfNotCacheable() {
261261
@Test
262262
public void testNotifiesNewCallbackOfResourceIfCallbackIsAddedDuringOnResourceReady() {
263263
final EngineJob<Object> job = harness.getJob();
264-
final ResourceCallback existingCallback = mock(ResourceCallback.class);
265-
final ResourceCallback newCallback = mock(ResourceCallback.class);
264+
final ResourceCallback existingCallback = mockResourceCallback();
265+
final ResourceCallback newCallback = mockResourceCallback();
266266

267267
doAnswer(
268268
new Answer<Void>() {
@@ -286,8 +286,8 @@ public Void answer(InvocationOnMock invocationOnMock) {
286286
public void testNotifiesNewCallbackOfExceptionIfCallbackIsAddedDuringOnException() {
287287
harness = new EngineJobHarness();
288288
final EngineJob<Object> job = harness.getJob();
289-
final ResourceCallback existingCallback = mock(ResourceCallback.class);
290-
final ResourceCallback newCallback = mock(ResourceCallback.class);
289+
final ResourceCallback existingCallback = mockResourceCallback();
290+
final ResourceCallback newCallback = mockResourceCallback();
291291

292292
doAnswer(
293293
new Answer<Void>() {
@@ -311,7 +311,7 @@ public Void answer(InvocationOnMock invocationOnMock) {
311311
@Test
312312
public void testRemovingCallbackDuringOnResourceReadyIsIgnoredIfCallbackHasAlreadyBeenCalled() {
313313
final EngineJob<Object> job = harness.getJob();
314-
final ResourceCallback cb = mock(ResourceCallback.class);
314+
final ResourceCallback cb = mockResourceCallback();
315315

316316
doAnswer(
317317
new Answer<Void>() {
@@ -335,7 +335,7 @@ public Void answer(InvocationOnMock invocationOnMock) {
335335
public void testRemovingCallbackDuringOnExceptionIsIgnoredIfCallbackHasAlreadyBeenCalled() {
336336
harness = new EngineJobHarness();
337337
final EngineJob<Object> job = harness.getJob();
338-
final ResourceCallback cb = mock(ResourceCallback.class);
338+
final ResourceCallback cb = mockResourceCallback();
339339

340340
doAnswer(
341341
new Answer<Void>() {
@@ -360,7 +360,7 @@ public Void answer(InvocationOnMock invocationOnMock) {
360360
public void
361361
testRemovingCallbackDuringOnResourceReadyPreventsCallbackFromBeingCalledIfNotYetCalled() {
362362
final EngineJob<Object> job = harness.getJob();
363-
final ResourceCallback notYetCalled = mock(ResourceCallback.class);
363+
final ResourceCallback notYetCalled = mockResourceCallback();
364364

365365
doAnswer(
366366
new Answer<Void>() {
@@ -384,7 +384,7 @@ public Void answer(InvocationOnMock invocationOnMock) {
384384
public void
385385
testRemovingCallbackDuringOnResourceReadyPreventsResourceFromBeingAcquiredForCallback() {
386386
final EngineJob<Object> job = harness.getJob();
387-
final ResourceCallback notYetCalled = mock(ResourceCallback.class);
387+
final ResourceCallback notYetCalled = mockResourceCallback();
388388

389389
doAnswer(
390390
new Answer<Void>() {
@@ -410,8 +410,8 @@ public Void answer(InvocationOnMock invocationOnMock) {
410410
public void testRemovingCallbackDuringOnExceptionPreventsCallbackFromBeingCalledIfNotYetCalled() {
411411
harness = new EngineJobHarness();
412412
final EngineJob<Object> job = harness.getJob();
413-
final ResourceCallback called = mock(ResourceCallback.class);
414-
final ResourceCallback notYetCalled = mock(ResourceCallback.class);
413+
final ResourceCallback called = mockResourceCallback();
414+
final ResourceCallback notYetCalled = mockResourceCallback();
415415

416416
doAnswer(
417417
new Answer<Void>() {
@@ -482,6 +482,12 @@ public void testSubmitsDecodeJobToUnlimitedSourceServiceWhenDecodingFromSourceOn
482482
verify(harness.decodeJob).run();
483483
}
484484

485+
private static ResourceCallback mockResourceCallback() {
486+
ResourceCallback result = mock(ResourceCallback.class);
487+
when(result.getLock()).thenReturn(result);
488+
return result;
489+
}
490+
485491
@SuppressWarnings("unchecked")
486492
private static class MultiCbHarness {
487493
final Key key = mock(Key.class);
@@ -524,7 +530,7 @@ public MultiCbHarness() {
524530
useAnimationPool,
525531
onlyRetrieveFromCache);
526532
for (int i = 0; i < numCbs; i++) {
527-
cbs.add(mock(ResourceCallback.class));
533+
cbs.add(mockResourceCallback());
528534
}
529535
for (ResourceCallback cb : cbs) {
530536
job.addCallback(cb, Executors.directExecutor());
@@ -537,7 +543,7 @@ private static class EngineJobHarness {
537543
final EngineJob.EngineResourceFactory factory = mock(EngineJob.EngineResourceFactory.class);
538544
final Key key = mock(Key.class);
539545
final Handler mainHandler = new Handler();
540-
final ResourceCallback cb = mock(ResourceCallback.class);
546+
final ResourceCallback cb = mockResourceCallback();
541547
final Resource<Object> resource = mockResource();
542548
final EngineResource<Object> engineResource = mock(EngineResource.class);
543549
final EngineJobListener engineJobListener = mock(EngineJobListener.class);

0 commit comments

Comments
 (0)
Please sign in to comment.