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 
25 namespace OHOS::Ace::ComponentTest {
26 
27 constexpr uint32_t period = 2000 / 4;
28 constexpr uint32_t delay_next_check = 1000 / 4;
29 constexpr uint32_t delay_double_confirm = 2000 / 4;
30 constexpr uint32_t delay_after_change = 5000 / 4;
31 
32 constexpr uint8_t max_idle_check_retry = 10;
33 
UpdatePipelineStatus()34 void UpdatePipelineStatus()
35 {
36     ComponentTestManagerImpl::Get()->pipelineStatusHolder.Update();
37 }
38 
VsyncCountFirstCheck()39 void 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 
VsyncCountSecondCheck()53 void 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 
Create()64 RefPtr<IdleMonitorThread> IdleMonitorThread::Create()
65 {
66     auto idleMonitorThread = MakeRefPtr<IdleMonitorThread>();
67     idleMonitorThread->thread = TaskRunnerAdapterFactory::Create(false, "IdleMonitorThread");
68     return idleMonitorThread;
69 }
70 
Stop()71 void IdleMonitorThread::Stop()
72 {
73     thread.Reset();
74 }
75 
SetIdleNotifycallback(IdleNotifycallback callback)76 void IdleMonitorThread::SetIdleNotifycallback(IdleNotifycallback callback)
77 {
78     callback_ = callback;
79 }
80 
SetTaskExecutor(RefPtr<TaskExecutor> taskExecutor)81 void IdleMonitorThread::SetTaskExecutor(RefPtr<TaskExecutor> taskExecutor)
82 {
83     taskExecutor_ = taskExecutor;
84 }
85 
PostInitializeTask()86 void IdleMonitorThread::PostInitializeTask()
87 {
88     thread->PostDelayedTask([this]() { PostCheckTask([this]() { VsyncCountFirstCheck(); }, period); }, period, {});
89 }
90 
PostCheckTask(std::function<void()>&& task, uint32_t delay)91 void IdleMonitorThread::PostCheckTask(std::function<void()>&& task, uint32_t delay)
92 {
93     thread->PostDelayedTask(std::move(task), delay, {});
94 }
95 
IdleWatcher(RefPtr<TaskExecutor> taskExecutor)96 IdleWatcher::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 
Destroy()105 void IdleWatcher::Destroy()
106 {
107     idleMonitorThread_->Stop();
108     std::lock_guard<std::mutex> lock(observersMutex_);
109     pendingIdleObservers_.clear();
110 }
111 
TriggerIdleNotification()112 void 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 
RequestNextIdleStatusNotification(IdleNotifycallback&& notifycallback, bool haveUIChange)132 void 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 
RequestContinuousIdleStatusNotification(IdleNotifycallback&& continuousIdleCallback)149 void IdleWatcher::RequestContinuousIdleStatusNotification(IdleNotifycallback&& continuousIdleCallback)
150 {
151     continuousIdleCallback_ = std::move(continuousIdleCallback);
152 }
153 
ClaimLongOperation()154 void IdleWatcher::ClaimLongOperation()
155 {
156     ComponentTestManagerImpl::Get()->pipelineStatusHolder.IncreaseLongOpt();
157 }
158 
LongOperationComplete()159 void IdleWatcher::LongOperationComplete()
160 {
161     ComponentTestManagerImpl::Get()->pipelineStatusHolder.DecreaseLongOpt();
162 }
163 } // namespace OHOS::Ace::ComponentTest
164