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); return buildBatteryGoodSlice(sliceBuilder, true);
} }
final List<BatteryTip> batteryTips = SliceBackgroundWorker.getInstance(mContext, final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
this).getResults(); final List<BatteryTip> batteryTips = worker != null ? worker.getResults() : null;
if (batteryTips == null) { if (batteryTips == null) {
// Because we need wait slice background worker return data // Because we need wait slice background worker return data

View File

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

View File

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