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

Commit 91451abb authored by zachh's avatar zachh Committed by android-build-merger
Browse files

Merge "Added timing to some more AnnotatedCallLog operations." am: 9ed12284 am: c80240f1

am: 0850896f

Change-Id: I81f849f846843536dba57d5fc6558a8f5af3c0c3
parents 17ecb7b4 0850896f
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -21,10 +21,15 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.Nullable;
import com.android.dialer.calllog.RefreshAnnotatedCallLogWorker.RefreshResult;
import com.android.dialer.calllog.constants.IntentNames;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DefaultFutureCallback;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.metrics.FutureTimer;
import com.android.dialer.metrics.Metrics;
import com.android.dialer.metrics.MetricsComponent;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
@@ -43,6 +48,7 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver {
  private static final long REFRESH_ANNOTATED_CALL_LOG_WAIT_MILLIS = 100L;

  private final RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker;
  private final FutureTimer futureTimer;

  @Nullable private Runnable refreshAnnotatedCallLogRunnable;

@@ -57,6 +63,7 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver {
  public RefreshAnnotatedCallLogReceiver(Context context) {
    refreshAnnotatedCallLogWorker =
        CallLogComponent.get(context).getRefreshAnnotatedCallLogWorker();
    futureTimer = MetricsComponent.get(context).futureTimer();
  }

  @Override
@@ -97,12 +104,14 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver {

    refreshAnnotatedCallLogRunnable =
        () -> {
          ListenableFuture<Void> future =
          ListenableFuture<RefreshResult> future =
              checkDirty
                  ? refreshAnnotatedCallLogWorker.refreshWithDirtyCheck()
                  : refreshAnnotatedCallLogWorker.refreshWithoutDirtyCheck();
          Futures.addCallback(
              future, new DefaultFutureCallback<>(), MoreExecutors.directExecutor());
          futureTimer.applyTiming(future, new EventNameFromResultFunction(checkDirty));
          // TODO(zachh): Should also log impression counts of RefreshResults.
        };

    ThreadUtil.getUiThreadHandler()
@@ -118,4 +127,29 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver {

    ThreadUtil.getUiThreadHandler().removeCallbacks(refreshAnnotatedCallLogRunnable);
  }

  private static class EventNameFromResultFunction implements Function<RefreshResult, String> {

    private final boolean checkDirty;

    private EventNameFromResultFunction(boolean checkDirty) {
      this.checkDirty = checkDirty;
    }

    @Override
    public String apply(RefreshResult refreshResult) {
      switch (refreshResult) {
        case NOT_DIRTY:
          return Metrics.REFRESH_NOT_DIRTY; // NOT_DIRTY implies forceRefresh is false
        case REBUILT_BUT_NO_CHANGES_NEEDED:
          return checkDirty
              ? Metrics.REFRESH_NO_CHANGES_NEEDED
              : Metrics.FORCE_REFRESH_NO_CHANGES_NEEDED;
        case REBUILT_AND_CHANGES_NEEDED:
          return checkDirty ? Metrics.REFRESH_CHANGES_NEEDED : Metrics.FORCE_REFRESH_CHANGES_NEEDED;
        default:
          throw new IllegalStateException("Unsupported result: " + refreshResult);
      }
    }
  }
}
+16 −7
Original line number Diff line number Diff line
@@ -79,23 +79,30 @@ public class RefreshAnnotatedCallLogWorker {
    this.lightweightExecutorService = lightweightExecutorService;
  }

  /** Result of refreshing the annotated call log. */
  public enum RefreshResult {
    NOT_DIRTY,
    REBUILT_BUT_NO_CHANGES_NEEDED,
    REBUILT_AND_CHANGES_NEEDED
  }

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

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

  private ListenableFuture<Void> refresh(boolean checkDirty) {
  private ListenableFuture<RefreshResult> refresh(boolean checkDirty) {
    LogUtil.i("RefreshAnnotatedCallLogWorker.refresh", "submitting serialized refresh request");
    return dialerFutureSerializer.submitAsync(
        () -> checkDirtyAndRebuildIfNecessary(checkDirty), lightweightExecutorService);
  }

  private ListenableFuture<Void> checkDirtyAndRebuildIfNecessary(boolean checkDirty) {
  private ListenableFuture<RefreshResult> checkDirtyAndRebuildIfNecessary(boolean checkDirty) {
    ListenableFuture<Boolean> forceRebuildFuture =
        backgroundExecutorService.submit(
            () -> {
@@ -139,7 +146,7 @@ public class RefreshAnnotatedCallLogWorker {
            return Futures.transformAsync(
                callLogState.isBuilt(), this::rebuild, MoreExecutors.directExecutor());
          }
          return Futures.immediateFuture(null);
          return Futures.immediateFuture(RefreshResult.NOT_DIRTY);
        },
        lightweightExecutorService);
  }
@@ -160,7 +167,7 @@ public class RefreshAnnotatedCallLogWorker {
    return isDirtyFuture;
  }

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

    // Start by filling the data sources--the system call log data source must go first!
@@ -225,7 +232,9 @@ public class RefreshAnnotatedCallLogWorker {
        unused -> {
          sharedPreferences.edit().putBoolean(SharedPrefKeys.FORCE_REBUILD, false).apply();
          callLogState.markBuilt();
          return null;
          return mutations.isEmpty()
              ? RefreshResult.REBUILT_BUT_NO_CHANGES_NEEDED
              : RefreshResult.REBUILT_AND_CHANGES_NEEDED;
        },
        backgroundExecutorService);
  }
+4 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.Ann
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.metrics.Metrics;
import com.android.dialer.metrics.MetricsComponent;
import java.util.ArrayList;
import java.util.Arrays;

@@ -153,6 +155,7 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
        Assert.checkArgument(
            selectionArgs == null, "selection args not supported for coalesced call log");
        Assert.checkArgument(sortOrder == null, "sort order not supported for coalesced call log");
        MetricsComponent.get(getContext()).metrics().startTimer(Metrics.NEW_CALL_LOG_COALESCE);
        try (Cursor allAnnotatedCallLogRows =
            queryBuilder.query(
                db,
@@ -168,6 +171,7 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
                  .coalesce(allAnnotatedCallLogRows);
          coalescedRows.setNotificationUri(
              getContext().getContentResolver(), CoalescedAnnotatedCallLog.CONTENT_URI);
          MetricsComponent.get(getContext()).metrics().stopTimer(Metrics.NEW_CALL_LOG_COALESCE);
          return coalescedRows;
        }
      default:
+25 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.support.annotation.IntDef;
import android.support.annotation.VisibleForTesting;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
import com.google.common.base.Function;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -72,7 +73,7 @@ public final class FutureTimer {
   * of tracking heavyweight operations (which is what this method is intended for).
   */
  public <T> void applyTiming(ListenableFuture<T> future, String eventName) {
    applyTiming(future, eventName, LogCatMode.DONT_LOG_VALUES);
    applyTiming(future, unused -> eventName, LogCatMode.DONT_LOG_VALUES);
  }

  /**
@@ -81,14 +82,35 @@ public final class FutureTimer {
   */
  public <T> void applyTiming(
      ListenableFuture<T> future, String eventName, @LogCatMode int logCatMode) {
    applyTiming(future, unused -> eventName, logCatMode);
  }

  /**
   * Overload of {@link #applyTiming(ListenableFuture, String)} that accepts a function which
   * specifies how to compute an event name from the result of the future.
   *
   * <p>This is useful when the event name depends on the result of the future.
   */
  public <T> void applyTiming(
      ListenableFuture<T> future, Function<T, String> eventNameFromResultFunction) {
    applyTiming(future, eventNameFromResultFunction, LogCatMode.DONT_LOG_VALUES);
  }

  private <T> void applyTiming(
      ListenableFuture<T> future,
      Function<T, String> eventNameFromResultFunction,
      @LogCatMode int logCatMode) {
    long startTime = SystemClock.elapsedRealtime();
    metrics.startTimer(eventName);
    Integer timerId = metrics.startUnnamedTimer();
    Futures.addCallback(
        future,
        new FutureCallback<T>() {
          @Override
          public void onSuccess(T result) {
            metrics.stopTimer(eventName);
            String eventName = eventNameFromResultFunction.apply(result);
            if (timerId != null) {
              metrics.stopUnnamedTimer(timerId, eventName);
            }
            long operationTime = SystemClock.elapsedRealtime() - startTime;

            // If the operation took a long time, do some WARNING logging.
+26 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.dialer.metrics;

import android.app.Application;
import android.support.annotation.Nullable;

/** Logs metrics. */
public interface Metrics {
@@ -36,6 +37,14 @@ public interface Metrics {
  String NEW_CALL_LOG_JANK_EVENT_NAME = "NewCallLog.Jank";

  // Events related to refreshing the annotated call log.
  String NEW_CALL_LOG_COALESCE = "NewCallLog.Coalesce";
  String REFRESH_NOT_DIRTY = "RefreshAnnotatedCallLogReceiver.NotDirty";
  String REFRESH_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.ChangesNeeded";
  String REFRESH_NO_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.NoChangesNeeded";
  String FORCE_REFRESH_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.ForceRefreshChangesNeeded";
  String FORCE_REFRESH_NO_CHANGES_NEEDED =
      "RefreshAnnotatedCallLogReceiver.ForceRefreshNoChangesNeeded";

  String INITIAL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.Fill";
  String INITIAL_ON_SUCCESSFUL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.OnSuccessfulFill";
  String INITIAL_APPLY_MUTATIONS_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.ApplyMutations";
@@ -61,6 +70,23 @@ public interface Metrics {
  /** Start a timer. */
  void startTimer(String timerEventName);

  /**
   * Starts a timer for which the name is not yet known.
   *
   * @return opaque identifier for the event which should be provided back to {@link
   *     #stopUnnamedTimer(int, String)} to stop the timer. Null if the timer cannot be started, for
   *     example because the user is locked.
   */
  @Nullable
  Integer startUnnamedTimer();

  /**
   * Stop a timer which was started with {@link #startUnnamedTimer()}.
   *
   * @param timerId the value returned in the corresponding call to {@link #startUnnamedTimer()}
   */
  void stopUnnamedTimer(int timerId, String timerEventName);

  /** Stop a timer. */
  void stopTimer(String timerEventName);

Loading