summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matt Buckley <mattbuckley@google.com> 2024-11-27 20:44:42 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-11-27 20:44:42 +0000
commitf52ff01ff46295f00551b5a80b3bf4bd89ccca2a (patch)
treefb0fdf623b9b160d2d8f523b28b1cb3d71902362
parent5870552967bf403229cf77448500c550f6563a32 (diff)
parentdf439a3a726d981af029eda75629c16036a3b89a (diff)
Merge "Add new surface binding and auto ADPF methods for ADPF Timeline API" into main
-rw-r--r--core/java/android/os/IHintManager.aidl6
-rw-r--r--core/java/android/os/IHintSession.aidl5
-rw-r--r--core/java/android/os/SessionCreationConfig.aidl8
-rw-r--r--native/android/libandroid.map.txt3
-rw-r--r--native/android/performance_hint.cpp160
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp3
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java97
8 files changed, 270 insertions, 13 deletions
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index f1936b5e0ff9..4a14a8d0faf8 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -64,4 +64,10 @@ interface IHintManager {
* Get Maximum number of graphics pipeline threads allowed per-app.
*/
int getMaxGraphicsPipelineThreadsCount();
+
+ /**
+ * Used by the JNI to pass an interface to the SessionManager;
+ * for internal use only.
+ */
+ oneway void passSessionManagerBinder(in IBinder sessionManager);
}
diff --git a/core/java/android/os/IHintSession.aidl b/core/java/android/os/IHintSession.aidl
index 6fd4f3c7c01a..e3f899de6d01 100644
--- a/core/java/android/os/IHintSession.aidl
+++ b/core/java/android/os/IHintSession.aidl
@@ -27,4 +27,9 @@ oneway interface IHintSession {
void sendHint(int hint);
void setMode(int mode, boolean enabled);
void reportActualWorkDuration2(in WorkDuration[] workDurations);
+
+ /**
+ * Used by apps to associate a session to a given set of layers
+ */
+ oneway void associateToLayers(in IBinder[] layerTokens);
}
diff --git a/core/java/android/os/SessionCreationConfig.aidl b/core/java/android/os/SessionCreationConfig.aidl
index cdc0ef461e0c..17147e43cf83 100644
--- a/core/java/android/os/SessionCreationConfig.aidl
+++ b/core/java/android/os/SessionCreationConfig.aidl
@@ -36,4 +36,12 @@ parcelable SessionCreationConfig {
* List of the modes to be enabled upon session creation.
*/
SessionMode[] modesToEnable;
+
+ /**
+ * List of layers to attach this session to.
+ *
+ * Note: DO NOT STORE THESE IN HintSessionManager, as
+ * it will break the layer lifecycle.
+ */
+ IBinder[] layerTokens;
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 7f555a868615..077d7d350064 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -376,6 +376,7 @@ LIBANDROID {
APerformanceHint_notifyWorkloadIncrease; # introduced=36
APerformanceHint_notifyWorkloadReset; # introduced=36
APerformanceHint_borrowSessionFromJava; # introduced=36
+ APerformanceHint_setNativeSurfaces; # introduced=36
AWorkDuration_create; # introduced=VanillaIceCream
AWorkDuration_release; # introduced=VanillaIceCream
AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
@@ -388,6 +389,8 @@ LIBANDROID {
ASessionCreationConfig_setTargetWorkDurationNanos; # introduced=36
ASessionCreationConfig_setPreferPowerEfficiency; # introduced=36
ASessionCreationConfig_setGraphicsPipeline; # introduced=36
+ ASessionCreationConfig_setNativeSurfaces; # introduced=36
+ ASessionCreationConfig_setUseAutoTiming; # introduced=36
local:
*;
};
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 883e139cca0a..608c01caee96 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -29,13 +29,19 @@
#include <aidl/android/os/SessionCreationConfig.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
+#include <android/native_window.h>
#include <android/performance_hint.h>
+#include <android/surface_control.h>
#include <android/trace.h>
#include <android_os.h>
#include <cutils/trace.h>
#include <fmq/AidlMessageQueue.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
#include <inttypes.h>
#include <jni_wrappers.h>
#include <performance_hint_private.h>
@@ -66,7 +72,12 @@ struct APerformanceHintSession;
constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
struct AWorkDuration : public hal::WorkDuration {};
-struct ASessionCreationConfig : public SessionCreationConfig {};
+struct ASessionCreationConfig : public SessionCreationConfig {
+ std::vector<wp<IBinder>> layers{};
+ bool hasMode(hal::SessionMode&& mode) {
+ return std::find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
+ }
+};
bool kForceGraphicsPipeline = false;
@@ -158,6 +169,11 @@ public:
FMQWrapper& getFMQWrapper();
bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
void initJava(JNIEnv* _Nonnull env);
+ ndk::ScopedAIBinder_Weak x;
+ template <class T>
+ static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
+ ASurfaceControl** controls, int numSurfaceControls,
+ std::vector<T>& out);
private:
// Necessary to create an empty binder object
@@ -203,6 +219,8 @@ public:
int setPreferPowerEfficiency(bool enabled);
int reportActualWorkDuration(AWorkDuration* workDuration);
bool isJava();
+ status_t setNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls,
+ int numSurfaceControls);
private:
friend struct APerformanceHintManager;
@@ -231,7 +249,7 @@ private:
static int64_t sIDCounter GUARDED_BY(sHintMutex);
// The most recent set of thread IDs
std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
- std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
+ std::optional<hal::SessionConfig> mSessionConfig;
// Tracing helpers
void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
void tracePowerEfficient(bool powerEfficient);
@@ -329,14 +347,12 @@ APerformanceHintSession* APerformanceHintManager::createSession(
ndk::ScopedAStatus ret;
hal::SessionConfig sessionConfig{.id = -1};
- SessionCreationConfig creationConfig{
+ ASessionCreationConfig creationConfig{{
.tids = std::vector<int32_t>(threadIds, threadIds + size),
.targetWorkDurationNanos = initialTargetWorkDurationNanos,
- };
+ }};
- return APerformanceHintManager::createSessionUsingConfig(static_cast<ASessionCreationConfig*>(
- &creationConfig),
- tag, isJava);
+ return APerformanceHintManager::createSessionUsingConfig(&creationConfig, tag, isJava);
}
APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
@@ -345,11 +361,29 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
hal::SessionConfig sessionConfig{.id = -1};
ndk::ScopedAStatus ret;
+ // Hold the tokens weakly until we actually need them,
+ // then promote them, then drop all strong refs after
+ if (!sessionCreationConfig->layers.empty()) {
+ for (auto&& layerIter = sessionCreationConfig->layers.begin();
+ layerIter != sessionCreationConfig->layers.end();) {
+ sp<IBinder> promoted = layerIter->promote();
+ if (promoted == nullptr) {
+ layerIter = sessionCreationConfig->layers.erase(layerIter);
+ } else {
+ sessionCreationConfig->layerTokens.push_back(
+ ndk::SpAIBinder(AIBinder_fromPlatformBinder(promoted.get())));
+ ++layerIter;
+ }
+ }
+ }
+
ret = mHintManager->createHintSessionWithConfig(mToken, tag,
*static_cast<SessionCreationConfig*>(
sessionCreationConfig),
&sessionConfig, &session);
+ sessionCreationConfig->layerTokens.clear();
+
if (!ret.isOk() || !session) {
ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
return nullptr;
@@ -679,6 +713,57 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor
return 0;
}
+status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, int numWindows,
+ ASurfaceControl** controls,
+ int numSurfaceControls) {
+ if (!mSessionConfig.has_value()) {
+ return ENOTSUP;
+ }
+
+ std::vector<sp<IBinder>> layerHandles;
+ APerformanceHintManager::layersFromNativeSurfaces<sp<IBinder>>(windows, numWindows, controls,
+ numSurfaceControls,
+ layerHandles);
+
+ std::vector<ndk::SpAIBinder> ndkLayerHandles;
+ for (auto&& handle : layerHandles) {
+ ndkLayerHandles.emplace_back(ndk::SpAIBinder(AIBinder_fromPlatformBinder(handle)));
+ }
+
+ mHintSession->associateToLayers(ndkLayerHandles);
+ return 0;
+}
+
+template <class T>
+void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
+ ASurfaceControl** controls,
+ int numSurfaceControls,
+ std::vector<T>& out) {
+ std::scoped_lock lock(sHintMutex);
+ if (windows != nullptr) {
+ std::vector<ANativeWindow*> windowVec(windows, windows + numWindows);
+ for (auto&& window : windowVec) {
+ Surface* surface = static_cast<Surface*>(window);
+ if (Surface::isValid(surface)) {
+ const sp<IBinder>& handle = surface->getSurfaceControlHandle();
+ if (handle != nullptr) {
+ out.push_back(handle);
+ }
+ }
+ }
+ }
+
+ if (controls != nullptr) {
+ std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls);
+ for (auto&& aSurfaceControl : controlVec) {
+ SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl);
+ if (control->isValid()) {
+ out.push_back(control->getHandle());
+ }
+ }
+ }
+}
+
// ===================================== FMQ wrapper implementation
bool FMQWrapper::isActive() {
@@ -963,8 +1048,7 @@ APerformanceHintSession* APerformanceHint_createSessionFromJava(
hal::SessionTag::APP, true);
}
-APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env,
- jobject sessionObj) {
+APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env, jobject sessionObj) {
VALIDATE_PTR(env)
VALIDATE_PTR(sessionObj)
return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
@@ -1065,6 +1149,14 @@ int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool
return session->notifyWorkloadReset(cpu, gpu, debugName);
}
+int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session,
+ ANativeWindow** nativeWindows, int nativeWindowsSize,
+ ASurfaceControl** surfaceControls, int surfaceControlsSize) {
+ VALIDATE_PTR(session)
+ return session->setNativeSurfaces(nativeWindows, nativeWindowsSize, surfaceControls,
+ surfaceControlsSize);
+}
+
AWorkDuration* AWorkDuration_create() {
return new AWorkDuration();
}
@@ -1180,6 +1272,11 @@ int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, b
config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
} else {
std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
+
+ // Remove automatic timing modes if we turn off GRAPHICS_PIPELINE,
+ // as it is a strict pre-requisite for these to run
+ std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
+ std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
}
return 0;
}
@@ -1197,3 +1294,48 @@ void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPe
void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
kForceNewHintBehavior = newBehavior;
}
+
+int ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config,
+ ANativeWindow** nativeWindows, int nativeWindowsSize,
+ ASurfaceControl** surfaceControls,
+ int surfaceControlsSize) {
+ VALIDATE_PTR(config)
+
+ APerformanceHintManager::layersFromNativeSurfaces<wp<IBinder>>(nativeWindows, nativeWindowsSize,
+ surfaceControls,
+ surfaceControlsSize,
+ config->layers);
+
+ if (config->layers.empty()) {
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu,
+ bool gpu) {
+ VALIDATE_PTR(config)
+ if ((cpu || gpu) && !config->hasMode(hal::SessionMode::GRAPHICS_PIPELINE)) {
+ ALOGE("Automatic timing is not supported unless graphics pipeline mode is enabled first");
+ return ENOTSUP;
+ }
+
+ if (config->hasMode(hal::SessionMode::AUTO_CPU)) {
+ if (!cpu) {
+ std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
+ }
+ } else if (cpu) {
+ config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_CPU));
+ }
+
+ if (config->hasMode(hal::SessionMode::AUTO_GPU)) {
+ if (!gpu) {
+ std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
+ }
+ } else if (gpu) {
+ config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_GPU));
+ }
+
+ return 0;
+}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index b00658052bde..b8f574f44338 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -83,6 +83,7 @@ public:
(override));
MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
(override));
+ MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
};
@@ -99,6 +100,8 @@ public:
MOCK_METHOD(ScopedAStatus, close, (), (override));
MOCK_METHOD(ScopedAStatus, reportActualWorkDuration2,
(const ::std::vector<hal::WorkDuration>& workDurations), (override));
+ MOCK_METHOD(ScopedAStatus, associateToLayers,
+ (const std::vector<::ndk::SpAIBinder>& in_layerTokens), (override));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
};
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c6b80cb5b125..08206150cebb 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -243,6 +243,7 @@ java_library_static {
"powerstats_flags_lib",
"locksettings_flags_lib",
"profiling_flags_lib",
+ "android.adpf.sessionmanager_aidl-java",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index aba15c83f907..0f6688f73c22 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -23,6 +23,7 @@ import static com.android.server.power.hint.Flags.adpfSessionTag;
import static com.android.server.power.hint.Flags.powerhintThreadCleanup;
import static com.android.server.power.hint.Flags.resetOnForkEnabled;
+import android.adpf.ISessionManager;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -193,6 +194,7 @@ public final class HintManagerService extends SystemService {
private final Object mCpuHeadroomLock = new Object();
+ private ISessionManager mSessionManager;
// this cache tracks the expiration time of the items and performs cleanup on lookup
private static class HeadroomCache<K, V> {
@@ -818,6 +820,23 @@ public final class HintManagerService extends SystemService {
for (int i = tokenMap.size() - 1; i >= 0; i--) {
// Will remove the session from tokenMap
ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(i);
+ IntArray closedSessionsForSf = new IntArray();
+ // Batch the closure call to SF for all the sessions that die
+ for (int j = sessionSet.size() - 1; j >= 0; j--) {
+ AppHintSession session = sessionSet.valueAt(j);
+ if (session.isTrackedBySf()) {
+ // Mark it as untracked so we don't untrack again on close
+ session.setTrackedBySf(false);
+ closedSessionsForSf.add(session.getSessionId());
+ }
+ }
+ if (mSessionManager != null) {
+ try {
+ mSessionManager.trackedSessionsDied(closedSessionsForSf.toArray());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to communicate with SessionManager");
+ }
+ }
for (int j = sessionSet.size() - 1; j >= 0; j--) {
sessionSet.valueAt(j).close();
}
@@ -1350,9 +1369,9 @@ public final class HintManagerService extends SystemService {
}
}
- final long sessionId = config.id != -1 ? config.id : halSessionPtr;
+ final long sessionIdForTracing = config.id != -1 ? config.id : halSessionPtr;
logPerformanceHintSessionAtom(
- callingUid, sessionId, durationNanos, tids, tag);
+ callingUid, sessionIdForTracing, durationNanos, tids, tag);
synchronized (mSessionSnapshotMapLock) {
// Update session snapshot upon session creation
@@ -1362,8 +1381,12 @@ public final class HintManagerService extends SystemService {
}
AppHintSession hs = null;
synchronized (mLock) {
+ Integer configId = null;
+ if (config.id != -1) {
+ configId = new Integer((int) config.id);
+ }
hs = new AppHintSession(callingUid, callingTgid, tag, tids,
- token, halSessionPtr, durationNanos);
+ token, halSessionPtr, durationNanos, configId);
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap =
mActiveSessions.get(callingUid);
if (tokenMap == null) {
@@ -1390,6 +1413,11 @@ public final class HintManagerService extends SystemService {
}
}
+ if (creationConfig.layerTokens != null
+ && creationConfig.layerTokens.length > 0) {
+ hs.associateToLayers(creationConfig.layerTokens);
+ }
+
synchronized (mThreadsUsageObject) {
mThreadsUsageMap.computeIfAbsent(callingUid, k -> new ArraySet<>());
ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
@@ -1566,6 +1594,15 @@ public final class HintManagerService extends SystemService {
}
@Override
+ public void passSessionManagerBinder(IBinder sessionManager) {
+ // Ensure caller is internal
+ if (Process.myUid() != Binder.getCallingUid()) {
+ return;
+ }
+ mSessionManager = ISessionManager.Stub.asInterface(sessionManager);
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
@@ -1688,6 +1725,8 @@ public final class HintManagerService extends SystemService {
protected boolean mHasBeenPowerEfficient;
protected boolean mHasBeenGraphicsPipeline;
protected boolean mShouldForcePause;
+ protected Integer mSessionId;
+ protected boolean mTrackedBySF;
enum SessionModes {
POWER_EFFICIENCY,
@@ -1696,7 +1735,7 @@ public final class HintManagerService extends SystemService {
protected AppHintSession(
int uid, int pid, int sessionTag, int[] threadIds, IBinder token,
- long halSessionPtr, long durationNanos) {
+ long halSessionPtr, long durationNanos, Integer sessionId) {
mUid = uid;
mPid = pid;
mTag = sessionTag;
@@ -1710,6 +1749,8 @@ public final class HintManagerService extends SystemService {
mHasBeenPowerEfficient = false;
mHasBeenGraphicsPipeline = false;
mShouldForcePause = false;
+ mSessionId = sessionId;
+ mTrackedBySF = false;
final boolean allowed = mUidObserver.isUidForeground(mUid);
updateHintAllowedByProcState(allowed);
try {
@@ -1799,6 +1840,19 @@ public final class HintManagerService extends SystemService {
} catch (NoSuchElementException ignored) {
Slogf.d(TAG, "Death link does not exist for session with UID " + mUid);
}
+ if (mTrackedBySF) {
+ if (mSessionManager != null) {
+ try {
+ mSessionManager.trackedSessionsDied(new int[]{mSessionId});
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Could not communicate with SessionManager", e);
+ }
+ mTrackedBySF = false;
+ } else {
+ Slog.e(TAG, "SessionManager is null but there are tracked sessions");
+ }
+ }
}
synchronized (mLock) {
ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(mUid);
@@ -1875,6 +1929,24 @@ public final class HintManagerService extends SystemService {
}
}
+ @Override
+ public void associateToLayers(IBinder[] layerTokens) {
+ synchronized (this) {
+ if (mSessionManager != null && mSessionId != null && layerTokens != null) {
+ // Sf only untracks a session when it dies
+ if (layerTokens.length > 0) {
+ mTrackedBySF = true;
+ }
+ try {
+ mSessionManager.associateSessionToLayers(mSessionId, mUid, layerTokens);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Could not communicate with SessionManager", e);
+ }
+ }
+ }
+ }
+
public void setThreads(@NonNull int[] tids) {
setThreadsInternal(tids, true);
}
@@ -2124,10 +2196,27 @@ public final class HintManagerService extends SystemService {
return mUid;
}
+ public boolean isTrackedBySf() {
+ synchronized (this) {
+ return mTrackedBySF;
+ }
+ }
+
+ public void setTrackedBySf(boolean tracked) {
+ synchronized (this) {
+ mTrackedBySF = tracked;
+ }
+ }
+
+
public int getTag() {
return mTag;
}
+ public Integer getSessionId() {
+ return mSessionId;
+ }
+
public long getTargetDurationNs() {
synchronized (this) {
return mTargetDurationNanos;