Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 658b9a9a authored by zachh's avatar zachh Committed by android-build-merger
Browse files

Merge "Track initial call log building metrics separately from incremental building metrics."

am: 3002ad66

Change-Id: I02a510faec754f87137573340ca2fbaba051822b
parents f99226c6 3002ad66
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.dialer.calllog;

import android.content.Context;
import android.content.SharedPreferences;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.inject.ApplicationContext;
@@ -39,7 +40,7 @@ public final class AnnotatedCallLogMigrator {
  private final Context appContext;
  private final SharedPreferences sharedPreferences;
  private final RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker;
  private final ListeningExecutorService backgorundExecutor;
  private final ListeningExecutorService backgroundExecutor;

  @Inject
  AnnotatedCallLogMigrator(
@@ -49,7 +50,7 @@ public final class AnnotatedCallLogMigrator {
      RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker) {
    this.appContext = appContext;
    this.sharedPreferences = sharedPreferences;
    this.backgorundExecutor = backgroundExecutor;
    this.backgroundExecutor = backgroundExecutor;
    this.refreshAnnotatedCallLogWorker = refreshAnnotatedCallLogWorker;
  }

@@ -58,13 +59,13 @@ public final class AnnotatedCallLogMigrator {
   * the latency the first time call log is shown.
   */
  public ListenableFuture<Void> migrate() {

    return Futures.transformAsync(
        shouldMigrate(),
        (shouldMigrate) -> {
          if (!shouldMigrate) {
            return Futures.immediateFuture(null);
          }
          LogUtil.i("AnnotatedCallLogMigrator.migrate", "migrating annotated call log");
          return Futures.transform(
              refreshAnnotatedCallLogWorker.refreshWithoutDirtyCheck(),
              (unused) -> {
@@ -77,7 +78,7 @@ public final class AnnotatedCallLogMigrator {
  }

  private ListenableFuture<Boolean> shouldMigrate() {
    return backgorundExecutor.submit(
    return backgroundExecutor.submit(
        () -> {
          if (!(ConfigProviderBindings.get(appContext)
              .getBoolean("is_nui_shortcut_enabled", false))) {
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.dialer.calllog;

import android.content.SharedPreferences;
import android.support.annotation.AnyThread;
import android.support.annotation.VisibleForTesting;
import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
import com.android.dialer.storage.Unencrypted;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;

/** Provides information about the state of the annotated call log. */
@ThreadSafe
public final class CallLogState {

  private static final String ANNOTATED_CALL_LOG_BUILT_PREF = "annotated_call_log_built";

  private final SharedPreferences sharedPreferences;
  private final ListeningExecutorService backgroundExecutor;

  @VisibleForTesting
  @Inject
  public CallLogState(
      @Unencrypted SharedPreferences sharedPreferences,
      @BackgroundExecutor ListeningExecutorService backgroundExecutor) {
    this.sharedPreferences = sharedPreferences;
    this.backgroundExecutor = backgroundExecutor;
  }

  /**
   * Mark the call log as having been built. This is written to disk the first time the annotated
   * call log has been built and shouldn't ever be reset unless the user clears data.
   */
  @AnyThread
  public void markBuilt() {
    sharedPreferences.edit().putBoolean(ANNOTATED_CALL_LOG_BUILT_PREF, true).apply();
  }

  /**
   * Returns true if the annotated call log has been built at least once.
   *
   * <p>It may not yet have been built if the user was just upgraded to the new call log, or they
   * just cleared data.
   */
  @AnyThread
  public ListenableFuture<Boolean> isBuilt() {
    return backgroundExecutor.submit(
        () -> sharedPreferences.getBoolean(ANNOTATED_CALL_LOG_BUILT_PREF, false));
  }
}
+51 −14
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -51,6 +52,7 @@ public class RefreshAnnotatedCallLogWorker {
  private final SharedPreferences sharedPreferences;
  private final MutationApplier mutationApplier;
  private final FutureTimer futureTimer;
  private final CallLogState callLogState;
  private final ListeningExecutorService backgroundExecutorService;
  private final ListeningExecutorService lightweightExecutorService;
  // Used to ensure that only one refresh flow runs at a time. (Note that
@@ -64,6 +66,7 @@ public class RefreshAnnotatedCallLogWorker {
      @Unencrypted SharedPreferences sharedPreferences,
      MutationApplier mutationApplier,
      FutureTimer futureTimer,
      CallLogState callLogState,
      @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
      @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
    this.appContext = appContext;
@@ -71,17 +74,18 @@ public class RefreshAnnotatedCallLogWorker {
    this.sharedPreferences = sharedPreferences;
    this.mutationApplier = mutationApplier;
    this.futureTimer = futureTimer;
    this.callLogState = callLogState;
    this.backgroundExecutorService = backgroundExecutorService;
    this.lightweightExecutorService = lightweightExecutorService;
  }

  /** Checks if the annotated call log is dirty and refreshes it if necessary. */
  public ListenableFuture<Void> refreshWithDirtyCheck() {
  ListenableFuture<Void> refreshWithDirtyCheck() {
    return refresh(true);
  }

  /** Refreshes the annotated call log, bypassing dirty checks. */
  public ListenableFuture<Void> refreshWithoutDirtyCheck() {
  ListenableFuture<Void> refreshWithoutDirtyCheck() {
    return refresh(false);
  }

@@ -131,7 +135,11 @@ public class RefreshAnnotatedCallLogWorker {
              "RefreshAnnotatedCallLogWorker.checkDirtyAndRebuildIfNecessary",
              "isDirty: %b",
              Preconditions.checkNotNull(isDirty));
          return isDirty ? rebuild() : Futures.immediateFuture(null);
          if (isDirty) {
            return Futures.transformAsync(
                callLogState.isBuilt(), this::rebuild, MoreExecutors.directExecutor());
          }
          return Futures.immediateFuture(null);
        },
        lightweightExecutorService);
  }
@@ -152,14 +160,13 @@ public class RefreshAnnotatedCallLogWorker {
    return isDirtyFuture;
  }

  private ListenableFuture<Void> rebuild() {
  private ListenableFuture<Void> rebuild(boolean isBuilt) {
    CallLogMutations mutations = new CallLogMutations();

    // Start by filling the data sources--the system call log data source must go first!
    CallLogDataSource systemCallLogDataSource = dataSources.getSystemCallLogDataSource();
    ListenableFuture<Void> fillFuture = systemCallLogDataSource.fill(appContext, mutations);
    String systemEventName =
        String.format(Metrics.FILL_TEMPLATE, systemCallLogDataSource.getClass().getSimpleName());
    String systemEventName = eventNameForFill(systemCallLogDataSource, isBuilt);
    futureTimer.applyTiming(fillFuture, systemEventName);

    // After the system call log data source is filled, call fill sequentially on each remaining
@@ -171,14 +178,14 @@ public class RefreshAnnotatedCallLogWorker {
              fillFuture,
              unused -> {
                ListenableFuture<Void> dataSourceFuture = dataSource.fill(appContext, mutations);
                String eventName =
                    String.format(Metrics.FILL_TEMPLATE, dataSource.getClass().getSimpleName());
                String eventName = eventNameForFill(dataSource, isBuilt);
                futureTimer.applyTiming(dataSourceFuture, eventName);
                return dataSourceFuture;
              },
              lightweightExecutorService);
    }
    futureTimer.applyTiming(fillFuture, Metrics.FILL_EVENT_NAME);

    futureTimer.applyTiming(fillFuture, eventNameForOverallFill(isBuilt));

    // After all data sources are filled, apply mutations (at this point "fillFuture" is the result
    // of filling the last data source).
@@ -188,7 +195,7 @@ public class RefreshAnnotatedCallLogWorker {
            unused -> {
              ListenableFuture<Void> mutationApplierFuture =
                  mutationApplier.applyToDatabase(mutations, appContext);
              futureTimer.applyTiming(mutationApplierFuture, Metrics.APPLY_MUTATIONS_EVENT_NAME);
              futureTimer.applyTiming(mutationApplierFuture, eventNameForApplyMutations(isBuilt));
              return mutationApplierFuture;
            },
            lightweightExecutorService);
@@ -203,13 +210,11 @@ public class RefreshAnnotatedCallLogWorker {
                  dataSources.getDataSourcesIncludingSystemCallLog()) {
                ListenableFuture<Void> dataSourceFuture = dataSource.onSuccessfulFill(appContext);
                onSuccessfulFillFutures.add(dataSourceFuture);
                String eventName =
                    String.format(
                        Metrics.ON_SUCCESSFUL_FILL_TEMPLATE, dataSource.getClass().getSimpleName());
                String eventName = eventNameForOnSuccessfulFill(dataSource, isBuilt);
                futureTimer.applyTiming(dataSourceFuture, eventName);
              }
              ListenableFuture<List<Void>> allFutures = Futures.allAsList(onSuccessfulFillFutures);
              futureTimer.applyTiming(allFutures, Metrics.ON_SUCCESSFUL_FILL_EVENT_NAME);
              futureTimer.applyTiming(allFutures, eventNameForOverallOnSuccessfulFill(isBuilt));
              return allFutures;
            },
            lightweightExecutorService);
@@ -219,8 +224,40 @@ public class RefreshAnnotatedCallLogWorker {
        onSuccessfulFillFuture,
        unused -> {
          sharedPreferences.edit().putBoolean(SharedPrefKeys.FORCE_REBUILD, false).apply();
          callLogState.markBuilt();
          return null;
        },
        backgroundExecutorService);
  }

  private static String eventNameForFill(CallLogDataSource dataSource, boolean isBuilt) {
    return String.format(
        !isBuilt ? Metrics.INITIAL_FILL_TEMPLATE : Metrics.FILL_TEMPLATE,
        dataSource.getClass().getSimpleName());
  }

  private static String eventNameForOverallFill(boolean isBuilt) {
    return !isBuilt ? Metrics.INITIAL_FILL_EVENT_NAME : Metrics.FILL_EVENT_NAME;
  }

  private static String eventNameForOnSuccessfulFill(
      CallLogDataSource dataSource, boolean isBuilt) {
    return String.format(
        !isBuilt
            ? Metrics.INITIAL_ON_SUCCESSFUL_FILL_TEMPLATE
            : Metrics.ON_SUCCESSFUL_FILL_TEMPLATE,
        dataSource.getClass().getSimpleName());
  }

  private static String eventNameForOverallOnSuccessfulFill(boolean isBuilt) {
    return !isBuilt
        ? Metrics.INITIAL_ON_SUCCESSFUL_FILL_EVENT_NAME
        : Metrics.ON_SUCCESSFUL_FILL_EVENT_NAME;
  }

  private static String eventNameForApplyMutations(boolean isBuilt) {
    return !isBuilt
        ? Metrics.INITIAL_APPLY_MUTATIONS_EVENT_NAME
        : Metrics.APPLY_MUTATIONS_EVENT_NAME;
  }
}
+13 −8
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ 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.composite.CompositePhoneLookup;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
import com.google.common.collect.ImmutableMap;
@@ -63,7 +64,7 @@ import javax.inject.Inject;
 */
public final class PhoneLookupDataSource implements CallLogDataSource {

  private final PhoneLookup<PhoneLookupInfo> phoneLookup;
  private final CompositePhoneLookup compositePhoneLookup;
  private final ListeningExecutorService backgroundExecutorService;
  private final ListeningExecutorService lightweightExecutorService;

@@ -86,10 +87,10 @@ public final class PhoneLookupDataSource implements CallLogDataSource {

  @Inject
  PhoneLookupDataSource(
      PhoneLookup<PhoneLookupInfo> phoneLookup,
      CompositePhoneLookup compositePhoneLookup,
      @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
      @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
    this.phoneLookup = phoneLookup;
    this.compositePhoneLookup = compositePhoneLookup;
    this.backgroundExecutorService = backgroundExecutorService;
    this.lightweightExecutorService = lightweightExecutorService;
  }
@@ -99,7 +100,8 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
    ListenableFuture<ImmutableSet<DialerPhoneNumber>> phoneNumbers =
        backgroundExecutorService.submit(
            () -> queryDistinctDialerPhoneNumbersFromAnnotatedCallLog(appContext));
    return Futures.transformAsync(phoneNumbers, phoneLookup::isDirty, lightweightExecutorService);
    return Futures.transformAsync(
        phoneNumbers, compositePhoneLookup::isDirty, lightweightExecutorService);
  }

  /**
@@ -157,10 +159,13 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
                queryPhoneLookupHistoryForNumbers(appContext, annotatedCallLogIdsByNumber.keySet()),
            backgroundExecutorService);

    // Use the original info map to generate the updated info map by delegating to phoneLookup.
    // Use the original info map to generate the updated info map by delegating to
    // compositePhoneLookup.
    ListenableFuture<ImmutableMap<DialerPhoneNumber, PhoneLookupInfo>> updatedInfoMapFuture =
        Futures.transformAsync(
            originalInfoMapFuture, phoneLookup::getMostRecentInfo, lightweightExecutorService);
            originalInfoMapFuture,
            compositePhoneLookup::getMostRecentInfo,
            lightweightExecutorService);

    // This is the computation that will use the result of all of the above.
    Callable<ImmutableMap<Long, PhoneLookupInfo>> computeRowsToUpdate =
@@ -241,7 +246,7 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
    // the AnnotatedCallLog and PhoneLookupHistory have been successfully updated.
    return Futures.transformAsync(
        writePhoneLookupHistory,
        unused -> phoneLookup.onSuccessfulBulkUpdate(),
        unused -> compositePhoneLookup.onSuccessfulBulkUpdate(),
        lightweightExecutorService);
  }

@@ -286,7 +291,7 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
  @MainThread
  @Override
  public void registerContentObservers(Context appContext) {
    phoneLookup.registerContentObservers(appContext);
    compositePhoneLookup.registerContentObservers(appContext);
  }

  private static ImmutableSet<DialerPhoneNumber>
+6 −5
Original line number Diff line number Diff line
@@ -31,8 +31,8 @@ import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
import com.android.dialer.common.concurrent.Annotations.Ui;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.inject.ApplicationContext;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.composite.CompositePhoneLookup;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
import com.google.common.collect.ImmutableMap;
@@ -68,7 +68,7 @@ public final class RealtimeRowProcessor {
  @VisibleForTesting static final long BATCH_WAIT_MILLIS = TimeUnit.SECONDS.toMillis(3);

  private final Context appContext;
  private final PhoneLookup<PhoneLookupInfo> phoneLookup;
  private final CompositePhoneLookup compositePhoneLookup;
  private final ListeningExecutorService uiExecutor;
  private final ListeningExecutorService backgroundExecutor;

@@ -83,11 +83,11 @@ public final class RealtimeRowProcessor {
      @ApplicationContext Context appContext,
      @Ui ListeningExecutorService uiExecutor,
      @BackgroundExecutor ListeningExecutorService backgroundExecutor,
      PhoneLookup<PhoneLookupInfo> phoneLookup) {
      CompositePhoneLookup compositePhoneLookup) {
    this.appContext = appContext;
    this.uiExecutor = uiExecutor;
    this.backgroundExecutor = backgroundExecutor;
    this.phoneLookup = phoneLookup;
    this.compositePhoneLookup = compositePhoneLookup;
  }

  /**
@@ -106,7 +106,8 @@ public final class RealtimeRowProcessor {
      return Futures.immediateFuture(applyPhoneLookupInfoToRow(cachedPhoneLookupInfo, row));
    }

    ListenableFuture<PhoneLookupInfo> phoneLookupInfoFuture = phoneLookup.lookup(row.number());
    ListenableFuture<PhoneLookupInfo> phoneLookupInfoFuture =
        compositePhoneLookup.lookup(row.number());
    return Futures.transform(
        phoneLookupInfoFuture,
        phoneLookupInfo -> {
Loading