Fix ConcurrentModificationException in SliceBackgroundWorker

- Two different threads could call SliceBackgroundWorker.getInstance()
  at the same time and caused ConcurrentModificationException
- Add a new API overloading getInstance for each slice to get a nullable
  worker since there is no result data then
- Only slice provider can create a new worker instance in main thread

Test: robotest
Change-Id: I560529bb6034ec22263418adeb7f3ccebf879196
Fixes: 121043385
This commit is contained in:
Jason Chiu
2019-01-04 15:12:19 +08:00
parent 6be224a919
commit e19658ac36
3 changed files with 19 additions and 9 deletions

View File

@@ -82,8 +82,8 @@ public class BatteryFixSlice implements CustomSliceable {
return buildBatteryGoodSlice(sliceBuilder, true);
}
final List<BatteryTip> batteryTips = SliceBackgroundWorker.getInstance(mContext,
this).getResults();
final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
final List<BatteryTip> batteryTips = worker != null ? worker.getResults() : null;
if (batteryTips == null) {
// Because we need wait slice background worker return data

View File

@@ -17,6 +17,7 @@
package com.android.settings.slices;
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.content.Context;
import android.net.Uri;
import android.util.ArrayMap;
@@ -58,20 +59,29 @@ public abstract class SliceBackgroundWorker<E> implements Closeable {
mUri = uri;
}
public Uri getUri() {
protected Uri getUri() {
return mUri;
}
/**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri}
* if exists
*/
@Nullable
public static SliceBackgroundWorker getInstance(Uri uri) {
return LIVE_WORKERS.get(uri);
}
/**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
* CustomSliceable}
*/
public static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
final Uri uri = sliceable.getUri();
final Class<? extends SliceBackgroundWorker> workerClass =
sliceable.getBackgroundWorkerClass();
SliceBackgroundWorker worker = LIVE_WORKERS.get(uri);
SliceBackgroundWorker worker = getInstance(uri);
if (worker == null) {
final Class<? extends SliceBackgroundWorker> workerClass =
sliceable.getBackgroundWorkerClass();
worker = createInstance(context, uri, workerClass);
LIVE_WORKERS.put(uri, worker);
}

View File

@@ -105,8 +105,8 @@ public class WifiSlice implements CustomSliceable {
return listBuilder.build();
}
final List<AccessPoint> results =
SliceBackgroundWorker.getInstance(mContext, this).getResults();
final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
final List<AccessPoint> results = worker != null ? worker.getResults() : null;
// Need a loading text when results are not ready.
boolean needLoadingRow = results == null;