1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.adservices.service.stats; 18 19 import android.annotation.NonNull; 20 21 import com.android.adservices.LogUtil; 22 23 import java.util.Objects; 24 25 import javax.annotation.concurrent.ThreadSafe; 26 27 /** 28 * Class for the Api Service Latency Calculator. This class uses a clock that its 29 * clock#elapsedRealtime() should always be monotonic to track the time points of a process. The 30 * {@link ApiServiceLatencyCalculator} constructor will set the {@link 31 * ApiServiceLatencyCalculator#mStartElapsedTimestamp}. Calling {@link 32 * ApiServiceLatencyCalculator#getApiServiceInternalFinalLatencyInMs()} will stop the time 33 * calculator and return the latency for the process by the start and stop elapsed timestamps. Once 34 * the calculator is stopped, the {@link ApiServiceLatencyCalculator#mStopElapsedTimestamp} will not 35 * be changed. Calling {@link ApiServiceLatencyCalculator#getApiServiceElapsedLatencyInMs()} will 36 * not stop the time calculator, only get the time elapsed since the start elapsed timestamp. 37 */ 38 @ThreadSafe 39 public class ApiServiceLatencyCalculator { 40 private final long mStartElapsedTimestamp; 41 private volatile long mStopElapsedTimestamp; 42 private volatile boolean mRunning; 43 private final Clock mClock; 44 ApiServiceLatencyCalculator(@onNull Clock clock)45 ApiServiceLatencyCalculator(@NonNull Clock clock) { 46 Objects.requireNonNull(clock); 47 mClock = clock; 48 mStartElapsedTimestamp = mClock.elapsedRealtime(); 49 mRunning = true; 50 LogUtil.v("ApiServiceLatencyCalculator has started at %d", mStartElapsedTimestamp); 51 } 52 53 /** 54 * Stops a {@link ApiServiceLatencyCalculator} instance from time calculation. If an instance is 55 * not running, calling this method will do nothing. 56 */ stop()57 private void stop() { 58 if (!mRunning) { 59 return; 60 } 61 synchronized (this) { 62 if (!mRunning) { 63 return; 64 } 65 mStopElapsedTimestamp = mClock.elapsedRealtime(); 66 mRunning = false; 67 LogUtil.v("ApiServiceLatencyCalculator stopped."); 68 } 69 } 70 71 /** @return the calculator's start timestamp since the system boots. */ getStartElapsedTimestamp()72 long getStartElapsedTimestamp() { 73 return mStartElapsedTimestamp; 74 } 75 76 /** 77 * @return the elapsed timestamp since the system boots if the {@link 78 * ApiServiceLatencyCalculator} instance is still running, otherwise the timestamp when it 79 * was stopped. 80 */ getServiceElapsedTimestamp()81 long getServiceElapsedTimestamp() { 82 if (mRunning) { 83 return mClock.elapsedRealtime(); 84 } 85 LogUtil.v("The ApiServiceLatencyCalculator instance has previously been stopped."); 86 return mStopElapsedTimestamp; 87 } 88 89 /** 90 * @return the api service elapsed time latency since {@link ApiServiceLatencyCalculator} starts 91 * in milliseconds on the service side. This method will not stop the {@link 92 * ApiServiceLatencyCalculator} and should be used for getting intermediate stage latency of 93 * a API process. 94 */ getApiServiceElapsedLatencyInMs()95 int getApiServiceElapsedLatencyInMs() { 96 return (int) (getServiceElapsedTimestamp() - mStartElapsedTimestamp); 97 } 98 99 /** 100 * @return the api service overall latency since the {@link ApiServiceLatencyCalculator} starts 101 * in milliseconds without binder latency, on the server side. This method will stop the 102 * calculator if still running and the returned latency value will no longer change once the 103 * calculator is stopped. It should be used to get the complete process latency of an API 104 * within the server side. 105 */ getApiServiceInternalFinalLatencyInMs()106 int getApiServiceInternalFinalLatencyInMs() { 107 stop(); 108 return getApiServiceElapsedLatencyInMs(); 109 } 110 } 111