Merge "Fix deadlock due to callbacks in ProgramList" into tm-qpr-dev

This commit is contained in:
Weilin Xu
2022-06-29 23:58:23 +00:00
committed by Android (Google) Code Review

View File

@@ -26,7 +26,6 @@ import android.os.Parcelable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@@ -173,38 +172,63 @@ public final class ProgramList implements AutoCloseable {
} }
} }
void apply(@NonNull Chunk chunk) { void apply(Chunk chunk) {
List<ProgramSelector.Identifier> removedList = new ArrayList<>();
List<ProgramSelector.Identifier> changedList = new ArrayList<>();
List<ProgramList.ListCallback> listCallbacksCopied;
List<OnCompleteListener> onCompleteListenersCopied = new ArrayList<>();
synchronized (mLock) { synchronized (mLock) {
if (mIsClosed) return; if (mIsClosed) return;
mIsComplete = false; mIsComplete = false;
listCallbacksCopied = new ArrayList<>(mListCallbacks);
if (chunk.isPurge()) { if (chunk.isPurge()) {
new HashSet<>(mPrograms.keySet()).stream().forEach(id -> removeLocked(id)); for (ProgramSelector.Identifier id : mPrograms.keySet()) {
removeLocked(id, removedList);
}
} }
chunk.getRemoved().stream().forEach(id -> removeLocked(id)); chunk.getRemoved().stream().forEach(id -> removeLocked(id, removedList));
chunk.getModified().stream().forEach(info -> putLocked(info)); chunk.getModified().stream().forEach(info -> putLocked(info, changedList));
if (chunk.isComplete()) { if (chunk.isComplete()) {
mIsComplete = true; mIsComplete = true;
mOnCompleteListeners.forEach(cb -> cb.onComplete()); onCompleteListenersCopied = new ArrayList<>(mOnCompleteListeners);
}
}
for (int i = 0; i < removedList.size(); i++) {
for (int cbIndex = 0; cbIndex < listCallbacksCopied.size(); cbIndex++) {
listCallbacksCopied.get(cbIndex).onItemRemoved(removedList.get(i));
}
}
for (int i = 0; i < changedList.size(); i++) {
for (int cbIndex = 0; cbIndex < listCallbacksCopied.size(); cbIndex++) {
listCallbacksCopied.get(cbIndex).onItemChanged(changedList.get(i));
}
}
if (chunk.isComplete()) {
for (int cbIndex = 0; cbIndex < onCompleteListenersCopied.size(); cbIndex++) {
onCompleteListenersCopied.get(cbIndex).onComplete();
} }
} }
} }
private void putLocked(@NonNull RadioManager.ProgramInfo value) { private void putLocked(RadioManager.ProgramInfo value,
List<ProgramSelector.Identifier> changedIdentifierList) {
ProgramSelector.Identifier key = value.getSelector().getPrimaryId(); ProgramSelector.Identifier key = value.getSelector().getPrimaryId();
mPrograms.put(Objects.requireNonNull(key), value); mPrograms.put(Objects.requireNonNull(key), value);
ProgramSelector.Identifier sel = value.getSelector().getPrimaryId(); ProgramSelector.Identifier sel = value.getSelector().getPrimaryId();
mListCallbacks.forEach(cb -> cb.onItemChanged(sel)); changedIdentifierList.add(sel);
} }
private void removeLocked(@NonNull ProgramSelector.Identifier key) { private void removeLocked(ProgramSelector.Identifier key,
List<ProgramSelector.Identifier> removedIdentifierList) {
RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key)); RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key));
if (removed == null) return; if (removed == null) return;
ProgramSelector.Identifier sel = removed.getSelector().getPrimaryId(); ProgramSelector.Identifier sel = removed.getSelector().getPrimaryId();
mListCallbacks.forEach(cb -> cb.onItemRemoved(sel)); removedIdentifierList.add(sel);
} }
/** /**