1/*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "component_test/idle_watcher.h"
17
18#include "component_test/component_test_manager_impl.h"
19
20#include "base/log/log.h"
21#include "base/thread/task_executor.h"
22#include "core/common/task_runner_adapter.h"
23#include "core/common/task_runner_adapter_factory.h"
24
25namespace OHOS::Ace::ComponentTest {
26
27constexpr uint32_t period = 2000 / 4;
28constexpr uint32_t delay_next_check = 1000 / 4;
29constexpr uint32_t delay_double_confirm = 2000 / 4;
30constexpr uint32_t delay_after_change = 5000 / 4;
31
32constexpr uint8_t max_idle_check_retry = 10;
33
34void UpdatePipelineStatus()
35{
36    ComponentTestManagerImpl::Get()->pipelineStatusHolder.Update();
37}
38
39void IdleMonitorThread::VsyncCountFirstCheck()
40{
41    if (ComponentTestManagerImpl::Get()->pipelineStatusHolder.Check()) {
42        PostCheckTask([this]() { VsyncCountSecondCheck(); }, delay_double_confirm);
43    } else {
44        if (ComponentTestManagerImpl::Get()->pipelineStatusHolder.RetryCounterReached(max_idle_check_retry)) {
45            LOGI("IdleMonitorThread wait pipeline idle timeout");
46            ComponentTestManagerImpl::Get()->pipelineStatusHolder.RetryCounterClear();
47            callback_();
48        }
49        PostCheckTask([this]() { VsyncCountFirstCheck(); }, delay_next_check);
50    }
51}
52
53void IdleMonitorThread::VsyncCountSecondCheck()
54{
55    if (ComponentTestManagerImpl::Get()->pipelineStatusHolder.Check()) {
56        ComponentTestManagerImpl::Get()->pipelineStatusHolder.RetryCounterClear();
57        callback_();
58        IdleMonitorThread::PostCheckTask([this]() { VsyncCountFirstCheck(); }, period);
59    } else {
60        IdleMonitorThread::PostCheckTask([this]() { VsyncCountFirstCheck(); }, delay_after_change);
61    }
62}
63
64RefPtr<IdleMonitorThread> IdleMonitorThread::Create()
65{
66    auto idleMonitorThread = MakeRefPtr<IdleMonitorThread>();
67    idleMonitorThread->thread = TaskRunnerAdapterFactory::Create(false, "IdleMonitorThread");
68    return idleMonitorThread;
69}
70
71void IdleMonitorThread::Stop()
72{
73    thread.Reset();
74}
75
76void IdleMonitorThread::SetIdleNotifycallback(IdleNotifycallback callback)
77{
78    callback_ = callback;
79}
80
81void IdleMonitorThread::SetTaskExecutor(RefPtr<TaskExecutor> taskExecutor)
82{
83    taskExecutor_ = taskExecutor;
84}
85
86void IdleMonitorThread::PostInitializeTask()
87{
88    thread->PostDelayedTask([this]() { PostCheckTask([this]() { VsyncCountFirstCheck(); }, period); }, period, {});
89}
90
91void IdleMonitorThread::PostCheckTask(std::function<void()>&& task, uint32_t delay)
92{
93    thread->PostDelayedTask(std::move(task), delay, {});
94}
95
96IdleWatcher::IdleWatcher(RefPtr<TaskExecutor> taskExecutor)
97{
98    keepingIdle_ = false;
99    idleMonitorThread_ = IdleMonitorThread::Create();
100    idleMonitorThread_->SetIdleNotifycallback([this] { TriggerIdleNotification(); });
101    idleMonitorThread_->SetTaskExecutor(taskExecutor);
102    idleMonitorThread_->PostInitializeTask();
103}
104
105void IdleWatcher::Destroy()
106{
107    idleMonitorThread_->Stop();
108    std::lock_guard<std::mutex> lock(observersMutex_);
109    pendingIdleObservers_.clear();
110}
111
112void IdleWatcher::TriggerIdleNotification()
113{
114    LOGI("Triggering idle notification");
115    keepingIdle_ = true;
116    if (pendingIdleObservers_.empty()) {
117        ComponentTestManagerImpl::Get()->pipelineStatusHolder.IdleCounterAdd();
118        if (ComponentTestManagerImpl::Get()->pipelineStatusHolder.IdleCounterReached(CONTINUOUS_IDLE_TIME) &&
119            continuousIdleCallback_) {
120            continuousIdleCallback_();
121            continuousIdleCallback_ = nullptr;
122        }
123    } else {
124        std::lock_guard<std::mutex> lock(observersMutex_);
125        for (IdleNotifycallback& notifycallback : pendingIdleObservers_) {
126            notifycallback();
127        }
128        pendingIdleObservers_.clear();
129    }
130}
131
132void IdleWatcher::RequestNextIdleStatusNotification(IdleNotifycallback&& notifycallback, bool haveUIChange)
133{
134    ComponentTestManagerImpl::Get()->pipelineStatusHolder.IdleCounterClear();
135    if (haveUIChange) {
136        notifycallback = [this, notifycallback]() {
137            keepingIdle_ = false;
138            notifycallback();
139        };
140    }
141    if (keepingIdle_) {
142        notifycallback();
143    } else {
144        std::lock_guard<std::mutex> lock(observersMutex_);
145        pendingIdleObservers_.emplace_back(notifycallback);
146    }
147}
148
149void IdleWatcher::RequestContinuousIdleStatusNotification(IdleNotifycallback&& continuousIdleCallback)
150{
151    continuousIdleCallback_ = std::move(continuousIdleCallback);
152}
153
154void IdleWatcher::ClaimLongOperation()
155{
156    ComponentTestManagerImpl::Get()->pipelineStatusHolder.IncreaseLongOpt();
157}
158
159void IdleWatcher::LongOperationComplete()
160{
161    ComponentTestManagerImpl::Get()->pipelineStatusHolder.DecreaseLongOpt();
162}
163} // namespace OHOS::Ace::ComponentTest
164