diff --git a/frameworks/native/appkit/BUILD.gn b/frameworks/native/appkit/BUILD.gn index d629f42d95f5afe6c04d3d2e5d02d2d48a83fe5d..0f355c9ad9b3a5bfaefbd140c5a37f68c5bcd2b8 100644 --- a/frameworks/native/appkit/BUILD.gn +++ b/frameworks/native/appkit/BUILD.gn @@ -104,6 +104,7 @@ ohos_shared_library("appkit_native") { "${ability_runtime_native_path}/appkit/app/application_env.cpp", "${ability_runtime_native_path}/appkit/app/application_env_impl.cpp", "${ability_runtime_native_path}/appkit/app/application_impl.cpp", + "${ability_runtime_native_path}/appkit/app/idle_time.cpp", "${ability_runtime_native_path}/appkit/app/main_thread.cpp", "${ability_runtime_native_path}/appkit/app/mix_stack_dumper.cpp", "${ability_runtime_native_path}/appkit/app/ohos_application.cpp", @@ -118,6 +119,7 @@ ohos_shared_library("appkit_native") { "${ability_runtime_innerkits_path}/uri_permission:uri_permission_mgr", "${ability_runtime_native_path}/appkit:app_context", "${ability_runtime_native_path}/appkit:app_context_utils", + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", ] public_deps = diff --git a/frameworks/native/appkit/app/idle_time.cpp b/frameworks/native/appkit/app/idle_time.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eec33e9a2acd856196428cc28e0c6994dfc52463 --- /dev/null +++ b/frameworks/native/appkit/app/idle_time.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#include "idle_time.h" + +#include "hilog_wrapper.h" +#include "transaction/rs_interfaces.h" + +namespace OHOS { +namespace AppExecFwk { +namespace { +constexpr int64_t PERIOD = 16666666; // ns +constexpr int64_t MS_PER_NS = 1000000; +constexpr int32_t TRY_COUNT_MAX = 6; +constexpr int32_t DEVIATION_MIN = 1000; // ns +std::shared_ptr receiver_ = nullptr; +} + +IdleTime::IdleTime(const std::shared_ptr &eventHandler, const std::shared_ptr &nativeEngine) +{ + eventHandler_ = eventHandler; + nativeEngine_ = nativeEngine; +} + +int64_t IdleTime::GetSysTimeNs() +{ + auto now = std::chrono::steady_clock::now().time_since_epoch(); + return std::chrono::duration_cast(now).count(); +} + +void IdleTime::OnVSync(int64_t timestamp, void* client) +{ + // only use for 60HZ + if (continueFailCount_ > TRY_COUNT_MAX) { + HILOG_ERROR("Only support 60HZ."); + return; + } + int64_t period = timestamp - firstVSyncTime_; + int64_t lastPeriod = period_ == 0 ? PERIOD : period_; + int64_t deviation = (period - lastPeriod) > 0 ? period - lastPeriod : lastPeriod - period; + if (deviation > MS_PER_NS) { // deviation greater than 1ms + RequestVSync(); + continueFailCount_++; + HILOG_DEBUG("fail count is %{public}d, timestamp is %{public}" PRId64 ", period is %{public}" PRId64, + continueFailCount_, timestamp, period); + } else { + if (eventHandler_ == nullptr) { + HILOG_ERROR("eventHandler_ is nullptr."); + return; + } + deviation = deviation < DEVIATION_MIN ? DEVIATION_MIN : deviation; + int64_t timeOut = lastPeriod / deviation; // up to 16666ms : MS_PER_NS / deviation * lastPeriod / MS_PER_NS + std::weak_ptr weak(shared_from_this()); + auto task = [weak]() { + auto idleTime = weak.lock(); + if (idleTime == nullptr) { + HILOG_ERROR("idleTime is nullptr."); + return; + } + idleTime->RequestVSync(); + }; + eventHandler_->PostTask(task, timeOut); + if (successCount_ > TRY_COUNT_MAX) { + period_ = (period & lastPeriod) + ((period ^ lastPeriod) >> 1); // average + } else { + period_ = PERIOD; + successCount_++; + HILOG_DEBUG("fail count is %{public}d, timestamp is %{public}" PRId64 ", period is %{public}" PRId64, + continueFailCount_, timestamp, period); + } + continueFailCount_ = 0; + } + + firstVSyncTime_ = timestamp; +} + +void IdleTime::RequestVSync() +{ + if (receiver_ == nullptr) { + auto& rsClient = Rosen::RSInterfaces::GetInstance(); + receiver_ = rsClient.CreateVSyncReceiver("ABILITY"); + if (receiver_ == nullptr) { + HILOG_ERROR("Create VSync receiver failed."); + return; + } + receiver_->Init(); + } + Rosen::VSyncReceiver::FrameCallback frameCallback = { + .userData_ = this, + .callback_ = [this](int64_t timestamp, void* data) { OnVSync(timestamp, data); }, + }; + receiver_->RequestNextVSync(frameCallback); +} + +void IdleTime::EventTask() +{ + if (firstVSyncTime_ == 0 || period_ == 0) { + PostTask(); + HILOG_ERROR("no VSync occur."); + return; + } + int64_t period = period_; + + int64_t occurTimestamp = GetSysTimeNs(); + int64_t numPeriod = (occurTimestamp - firstVSyncTime_) / period; + int64_t lastVSyncTime = numPeriod * period + firstVSyncTime_; + int64_t elapsedTime = occurTimestamp - lastVSyncTime; + int64_t idleTime = period - elapsedTime; + // set runtime + if (nativeEngine_ == nullptr) { + HILOG_ERROR("nativeEngine_ is nullptr."); + return; + } + nativeEngine_->NotifyIdleTime(idleTime / MS_PER_NS); + PostTask(); +} + +void IdleTime::PostTask() +{ + if (continueFailCount_ > TRY_COUNT_MAX) { + HILOG_ERROR("Only support 60HZ."); + return; + } + + if (eventHandler_ == nullptr) { + HILOG_ERROR("eventHandler_ is nullptr."); + return; + } + std::weak_ptr weak(shared_from_this()); + auto task = [weak]() { + auto idleTime = weak.lock(); + if (idleTime == nullptr) { + HILOG_ERROR("idleTime is nullptr."); + return; + } + idleTime->EventTask(); + }; + eventHandler_->PostTask(task, EventQueue::Priority::IDLE); +} + +void IdleTime::Start() +{ + RequestVSync(); + PostTask(); +} +} // AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index 88e7736c9415598f0fa09bb73c01b67feff773cd..aaedbd1847e76bdad2a94e7853ea7bfb7cffacd4 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -1119,6 +1119,9 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con LoadAllExtensions(jsEngine, "system/lib/extensionability", bundleInfo); #endif } + std::shared_ptr nativeEngine(&jsEngine); + idleTime_ = std::make_shared(mainHandler_, nativeEngine); + idleTime_->Start(); } auto usertestInfo = appLaunchData.GetUserTestInfo(); diff --git a/interfaces/kits/native/appkit/app/idle_time.h b/interfaces/kits/native/appkit/app/idle_time.h new file mode 100644 index 0000000000000000000000000000000000000000..2844a268301a91eaf32347ecfb2ba3767d106a5f --- /dev/null +++ b/interfaces/kits/native/appkit/app/idle_time.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_IDLE_TIME_H +#define OHOS_ABILITY_RUNTIME_IDLE_TIME_H + +#include "event_handler.h" +#include "native_engine/native_engine.h" + +namespace OHOS { +namespace AppExecFwk { +class IdleTime : public std::enable_shared_from_this { +public: + IdleTime(const std::shared_ptr &eventHandler, const std::shared_ptr &nativeEngine); + ~IdleTime() = default; + void Start(); + +private: + int64_t GetSysTimeNs(); + void OnVSync(int64_t nanoTimestamp, void* client); + void RequestVSync(); + void EventTask(); + void PostTask(); + + int64_t firstVSyncTime_ = 0; + int64_t period_ = 0; + int32_t continueFailCount_ = 0; + int32_t successCount_ = 0; + std::shared_ptr eventHandler_; + std::shared_ptr nativeEngine_; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_IDLE_TIME_H \ No newline at end of file diff --git a/interfaces/kits/native/appkit/app/main_thread.h b/interfaces/kits/native/appkit/app/main_thread.h index 188d426b70df68a90d89829d33310b0f363b1d26..023912d131dccbe1184d8ee7fe72fba7dd484ede 100644 --- a/interfaces/kits/native/appkit/app/main_thread.h +++ b/interfaces/kits/native/appkit/app/main_thread.h @@ -20,6 +20,7 @@ #include #include "event_handler.h" #include "extension_config_mgr.h" +#include "idle_time.h" #include "inner_event.h" #include "app_scheduler_host.h" #include "app_mgr_interface.h" @@ -426,8 +427,8 @@ private: /** * @brief Load all extension so - * - * @param nativeEngine nativeEngine instance + * + * @param nativeEngine nativeEngine instance * @param filePath extension so file path * @param bundleInfo application bundle information */ @@ -445,7 +446,7 @@ private: /** * @brief Update current process extension type - * + * * @param abilityRecord current running ability record */ void UpdateProcessExtensionType(const std::shared_ptr &abilityRecord); @@ -549,6 +550,7 @@ private: std::vector fileEntries_; std::vector nativeFileEntries_; std::vector handleAbilityLib_; // the handler of ACE Library. + std::shared_ptr idleTime_ = nullptr; #endif // ABILITY_LIBRARY_LOADER #ifdef APPLICATION_LIBRARY_LOADER void *handleAppLib_ = nullptr; // the handler of ACE Library.