no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / hal / android / AndroidPerformanceHintManager.cpp
bloba9507a82724b00c85af7116898d789e4aec56367
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "Hal.h"
8 #include "HalLog.h"
9 #include "HalTypes.h"
11 #include "AndroidBuild.h"
13 #include <dlfcn.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <sys/types.h>
18 typedef struct APerformanceHintManager APerformanceHintManager;
19 typedef struct APerformanceHintSession APerformanceHintSession;
21 namespace mozilla {
22 namespace hal_impl {
24 #define LOAD_FN(api, lib, name) \
25 do { \
26 api->m##name = reinterpret_cast<Fn##name>(dlsym(handle, #name)); \
27 if (!api->m##name) { \
28 HAL_ERR("Failed to load %s", #name); \
29 return nullptr; \
30 } \
31 } while (false)
33 class PerformanceHintManagerApi final {
34 public:
35 static PerformanceHintManagerApi* Get() {
36 // C++ guarantees local static variable initialization is thread safe
37 static UniquePtr<PerformanceHintManagerApi> api = Create();
38 return api.get();
41 APerformanceHintManager* APerformanceHint_getManager() const {
42 return mAPerformanceHint_getManager();
45 APerformanceHintSession* APerformanceHint_createSession(
46 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
47 int64_t initialTargetWorkDurationNanos) const {
48 return mAPerformanceHint_createSession(manager, threadIds, size,
49 initialTargetWorkDurationNanos);
52 int APerformanceHint_updateTargetWorkDuration(
53 APerformanceHintSession* session, int64_t targetDurationNanos) const {
54 return mAPerformanceHint_updateTargetWorkDuration(session,
55 targetDurationNanos);
58 int APerformanceHint_reportActualWorkDuration(
59 APerformanceHintSession* session, int64_t actualDurationNanos) const {
60 return mAPerformanceHint_reportActualWorkDuration(session,
61 actualDurationNanos);
64 void APerformanceHint_closeSession(APerformanceHintSession* session) const {
65 mAPerformanceHint_closeSession(session);
68 private:
69 PerformanceHintManagerApi() = default;
71 static UniquePtr<PerformanceHintManagerApi> Create() {
72 if (mozilla::jni::GetAPIVersion() < __ANDROID_API_T__) {
73 return nullptr;
76 void* const handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
77 if (!handle) {
78 HAL_ERR("Failed to open libandroid.so");
79 return nullptr;
82 auto api = WrapUnique(new PerformanceHintManagerApi());
83 LOAD_FN(api, handle, APerformanceHint_getManager);
84 LOAD_FN(api, handle, APerformanceHint_createSession);
85 LOAD_FN(api, handle, APerformanceHint_updateTargetWorkDuration);
86 LOAD_FN(api, handle, APerformanceHint_reportActualWorkDuration);
87 LOAD_FN(api, handle, APerformanceHint_closeSession);
89 return api;
92 using FnAPerformanceHint_getManager = APerformanceHintManager* (*)();
93 using FnAPerformanceHint_createSession =
94 APerformanceHintSession* (*)(APerformanceHintManager* manager,
95 const int32_t* threadIds, size_t size,
96 int64_t initialTargetWorkDurationNanos);
97 using FnAPerformanceHint_updateTargetWorkDuration =
98 int (*)(APerformanceHintSession* session, int64_t targetDurationNanos);
99 using FnAPerformanceHint_reportActualWorkDuration =
100 int (*)(APerformanceHintSession* session, int64_t actualDurationNanos);
101 using FnAPerformanceHint_closeSession =
102 void (*)(APerformanceHintSession* session);
104 FnAPerformanceHint_getManager mAPerformanceHint_getManager = nullptr;
105 FnAPerformanceHint_createSession mAPerformanceHint_createSession = nullptr;
106 FnAPerformanceHint_updateTargetWorkDuration
107 mAPerformanceHint_updateTargetWorkDuration = nullptr;
108 FnAPerformanceHint_reportActualWorkDuration
109 mAPerformanceHint_reportActualWorkDuration = nullptr;
110 FnAPerformanceHint_closeSession mAPerformanceHint_closeSession = nullptr;
113 class AndroidPerformanceHintSession final : public hal::PerformanceHintSession {
114 public:
115 // Creates a PerformanceHintSession wrapping the provided NDK
116 // APerformanceHintSession instance. This assumes ownership of aSession,
117 // therefore the caller must not close the session itself.
118 explicit AndroidPerformanceHintSession(APerformanceHintSession* aSession)
119 : mSession(aSession) {}
121 AndroidPerformanceHintSession(AndroidPerformanceHintSession& aOther) = delete;
122 AndroidPerformanceHintSession(AndroidPerformanceHintSession&& aOther) {
123 mSession = aOther.mSession;
124 aOther.mSession = nullptr;
127 ~AndroidPerformanceHintSession() {
128 if (mSession) {
129 PerformanceHintManagerApi::Get()->APerformanceHint_closeSession(mSession);
133 void UpdateTargetWorkDuration(TimeDuration aDuration) override {
134 PerformanceHintManagerApi::Get()->APerformanceHint_updateTargetWorkDuration(
135 mSession, aDuration.ToMicroseconds() * 1000);
138 void ReportActualWorkDuration(TimeDuration aDuration) override {
139 PerformanceHintManagerApi::Get()->APerformanceHint_reportActualWorkDuration(
140 mSession, aDuration.ToMicroseconds() * 1000);
143 private:
144 APerformanceHintSession* mSession;
147 static APerformanceHintManager* InitManager() {
148 const auto* api = PerformanceHintManagerApi::Get();
149 if (!api) {
150 return nullptr;
153 // At the time of writing we are only aware of PerformanceHintManager being
154 // implemented on Tensor devices (Pixel 6 and 7 families). On most devices
155 // createSession() will simply return null. However, on some devices
156 // createSession() does return a session but scheduling does not appear to be
157 // affected in any way. Rather than pretending to the caller that
158 // PerformanceHintManager is available on such devices, return null allowing
159 // them to use another means of achieving the performance they require.
160 const auto socManufacturer = java::sdk::Build::SOC_MANUFACTURER()->ToString();
161 if (!socManufacturer.EqualsASCII("Google")) {
162 return nullptr;
165 return api->APerformanceHint_getManager();
168 UniquePtr<hal::PerformanceHintSession> CreatePerformanceHintSession(
169 const nsTArray<PlatformThreadHandle>& aThreads,
170 mozilla::TimeDuration aTargetWorkDuration) {
171 // C++ guarantees local static variable initialization is thread safe
172 static APerformanceHintManager* manager = InitManager();
174 if (!manager) {
175 return nullptr;
178 const auto* api = PerformanceHintManagerApi::Get();
180 nsTArray<pid_t> tids(aThreads.Length());
181 std::transform(aThreads.cbegin(), aThreads.cend(), MakeBackInserter(tids),
182 [](pthread_t handle) { return pthread_gettid_np(handle); });
184 APerformanceHintSession* session = api->APerformanceHint_createSession(
185 manager, tids.Elements(), tids.Length(),
186 aTargetWorkDuration.ToMicroseconds() * 1000);
187 if (!session) {
188 return nullptr;
191 return MakeUnique<AndroidPerformanceHintSession>(session);
194 } // namespace hal_impl
195 } // namespace mozilla