summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/calllog/datasources
diff options
context:
space:
mode:
authorzachh <zachh@google.com>2017-12-06 20:33:23 -0800
committerCopybara-Service <copybara-piper@google.com>2017-12-07 18:31:07 -0800
commit17edc22de11f772a1efe91a9c6b7b4fd7e5d3416 (patch)
tree981164a399e84d414bdff43f0fa8ca1f8573536c /java/com/android/dialer/calllog/datasources
parentd28981d41c3691fc9fa5204e1d02fa4f2d818b43 (diff)
Made PhoneLookupDataSource implementation async.
We were previously calling get() which can cause deadlocks. Bug: 34672501 Test: existing PiperOrigin-RevId: 178192772 Change-Id: Id9088b12b765307c778d101d847cb1016ea828d1
Diffstat (limited to 'java/com/android/dialer/calllog/datasources')
-rw-r--r--java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java144
1 files changed, 87 insertions, 57 deletions
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
index 9606b8e77..17a09ce47 100644
--- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
@@ -30,6 +30,7 @@ import com.android.dialer.calllog.datasources.CallLogDataSource;
import com.android.dialer.calllog.datasources.CallLogMutations;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
+import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.PhoneLookupSelector;
@@ -38,6 +39,7 @@ import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
@@ -47,7 +49,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Callable;
import javax.inject.Inject;
/**
@@ -58,35 +60,24 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
private final PhoneLookup phoneLookup;
private final ListeningExecutorService backgroundExecutorService;
+ private final ListeningExecutorService lightweightExecutorService;
@Inject
PhoneLookupDataSource(
PhoneLookup phoneLookup,
- @BackgroundExecutor ListeningExecutorService backgroundExecutorService) {
+ @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
+ @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
this.phoneLookup = phoneLookup;
this.backgroundExecutorService = backgroundExecutorService;
+ this.lightweightExecutorService = lightweightExecutorService;
}
@Override
public ListenableFuture<Boolean> isDirty(Context appContext) {
- return backgroundExecutorService.submit(() -> isDirtyInternal(appContext));
- }
-
- @Override
- public ListenableFuture<Void> fill(Context appContext, CallLogMutations mutations) {
- return backgroundExecutorService.submit(() -> fillInternal(appContext, mutations));
- }
-
- @Override
- public ListenableFuture<Void> onSuccessfulFill(Context appContext) {
- return backgroundExecutorService.submit(this::onSuccessfulFillInternal);
- }
-
- @WorkerThread
- private boolean isDirtyInternal(Context appContext) throws Exception {
- ImmutableSet<DialerPhoneNumber> uniqueDialerPhoneNumbers =
- queryDistinctDialerPhoneNumbersFromAnnotatedCallLog(appContext);
- return phoneLookup.isDirty(uniqueDialerPhoneNumbers).get();
+ ListenableFuture<ImmutableSet<DialerPhoneNumber>> phoneNumbers =
+ backgroundExecutorService.submit(
+ () -> queryDistinctDialerPhoneNumbersFromAnnotatedCallLog(appContext));
+ return Futures.transformAsync(phoneNumbers, phoneLookup::isDirty, lightweightExecutorService);
}
/**
@@ -115,43 +106,82 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
* </ul>
* </ul>
*/
- @WorkerThread
- private Void fillInternal(Context appContext, CallLogMutations mutations) {
- Map<DialerPhoneNumber, Set<Long>> annotatedCallLogIdsByNumber =
- queryIdAndNumberFromAnnotatedCallLog(appContext);
- ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> originalPhoneLookupInfosByNumber =
- queryPhoneLookupHistoryForNumbers(appContext, annotatedCallLogIdsByNumber.keySet());
- ImmutableMap.Builder<Long, PhoneLookupInfo> originalPhoneLookupHistoryDataByAnnotatedCallLogId =
- ImmutableMap.builder();
- for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry :
- originalPhoneLookupInfosByNumber.entrySet()) {
- DialerPhoneNumber dialerPhoneNumber = entry.getKey();
- PhoneLookupInfo phoneLookupInfo = entry.getValue();
- for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) {
- originalPhoneLookupHistoryDataByAnnotatedCallLogId.put(id, phoneLookupInfo);
- }
- }
- populateInserts(originalPhoneLookupHistoryDataByAnnotatedCallLogId.build(), mutations);
-
- ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> updatedInfoMap;
- try {
- updatedInfoMap =
- phoneLookup.getMostRecentPhoneLookupInfo(originalPhoneLookupInfosByNumber).get();
- } catch (InterruptedException | ExecutionException e) {
- throw new IllegalStateException(e);
- }
- ImmutableMap.Builder<Long, PhoneLookupInfo> rowsToUpdate = ImmutableMap.builder();
- for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : updatedInfoMap.entrySet()) {
- DialerPhoneNumber dialerPhoneNumber = entry.getKey();
- PhoneLookupInfo upToDateInfo = entry.getValue();
- if (!originalPhoneLookupInfosByNumber.get(dialerPhoneNumber).equals(upToDateInfo)) {
- for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) {
- rowsToUpdate.put(id, upToDateInfo);
- }
- }
- }
- updateMutations(rowsToUpdate.build(), mutations);
- return null;
+ @Override
+ public ListenableFuture<Void> fill(Context appContext, CallLogMutations mutations) {
+ // First query information from annotated call log.
+ ListenableFuture<Map<DialerPhoneNumber, Set<Long>>> annotatedCallLogIdsByNumberFuture =
+ backgroundExecutorService.submit(() -> queryIdAndNumberFromAnnotatedCallLog(appContext));
+
+ // Use it to create the original info map.
+ ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> originalInfoMapFuture =
+ Futures.transform(
+ annotatedCallLogIdsByNumberFuture,
+ annotatedCallLogIdsByNumber ->
+ queryPhoneLookupHistoryForNumbers(appContext, annotatedCallLogIdsByNumber.keySet()),
+ backgroundExecutorService);
+
+ // Use the original info map to generate the updated info map by delegating to phoneLookup.
+ ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> updatedInfoMapFuture =
+ Futures.transformAsync(
+ originalInfoMapFuture,
+ phoneLookup::getMostRecentPhoneLookupInfo,
+ lightweightExecutorService);
+
+ // This is the computation that will use the result of all of the above.
+ Callable<ImmutableMap<Long, PhoneLookupInfo>> computeRowsToUpdate =
+ () -> {
+ // These get() calls are safe because we are using whenAllSucceed below.
+ Map<DialerPhoneNumber, Set<Long>> annotatedCallLogIdsByNumber =
+ annotatedCallLogIdsByNumberFuture.get();
+ ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> originalInfoMap =
+ originalInfoMapFuture.get();
+ ImmutableMap<DialerPhoneNumber, PhoneLookupInfo> updatedInfoMap =
+ updatedInfoMapFuture.get();
+
+ // First populate the insert mutations
+ ImmutableMap.Builder<Long, PhoneLookupInfo>
+ originalPhoneLookupHistoryDataByAnnotatedCallLogId = ImmutableMap.builder();
+ for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : originalInfoMap.entrySet()) {
+ DialerPhoneNumber dialerPhoneNumber = entry.getKey();
+ PhoneLookupInfo phoneLookupInfo = entry.getValue();
+ for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) {
+ originalPhoneLookupHistoryDataByAnnotatedCallLogId.put(id, phoneLookupInfo);
+ }
+ }
+ populateInserts(originalPhoneLookupHistoryDataByAnnotatedCallLogId.build(), mutations);
+
+ // Now compute the rows to update.
+ ImmutableMap.Builder<Long, PhoneLookupInfo> rowsToUpdate = ImmutableMap.builder();
+ for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : updatedInfoMap.entrySet()) {
+ DialerPhoneNumber dialerPhoneNumber = entry.getKey();
+ PhoneLookupInfo upToDateInfo = entry.getValue();
+ if (!originalInfoMap.get(dialerPhoneNumber).equals(upToDateInfo)) {
+ for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) {
+ rowsToUpdate.put(id, upToDateInfo);
+ }
+ }
+ }
+ return rowsToUpdate.build();
+ };
+
+ ListenableFuture<ImmutableMap<Long, PhoneLookupInfo>> rowsToUpdateFuture =
+ Futures.whenAllSucceed(
+ annotatedCallLogIdsByNumberFuture, updatedInfoMapFuture, originalInfoMapFuture)
+ .call(computeRowsToUpdate, lightweightExecutorService);
+
+ // Finally apply the computed rows to update to mutations.
+ return Futures.transform(
+ rowsToUpdateFuture,
+ rowsToUpdate -> {
+ updateMutations(rowsToUpdate, mutations);
+ return null;
+ },
+ lightweightExecutorService);
+ }
+
+ @Override
+ public ListenableFuture<Void> onSuccessfulFill(Context appContext) {
+ return backgroundExecutorService.submit(this::onSuccessfulFillInternal);
}
@WorkerThread