#define FML_USED_ON_EMBEDDER
#include "base/include/fml/message_loop_impl.h"
#include <algorithm>
#include <vector>
#include "base/include/fml/fml_trace_event_def.h"
#include "base/include/timer/time_utils.h"
#include "base/src/base_trace/base_trace_event_def.h"
#include "base/src/base_trace/trace_event.h"
#include "build/build_config.h"
namespace lynx {
namespace fml {
MessageLoopImpl::MessageLoopImpl()
: task_queue_(MessageLoopTaskQueues::GetInstance()),
internal_queue_id_(task_queue_->CreateTaskQueue()),
terminated_(false),
restriction_duration_(fml::TimeDelta::Max()) {
Bind(internal_queue_id_);
}
MessageLoopImpl::~MessageLoopImpl() {
task_queue_->Dispose(internal_queue_id_);
}
bool MessageLoopImpl::PostTask(base::closure task, fml::TimePoint target_time,
fml::TaskSourceGrade task_source_grade,
bool instant_task_hint) {
if (terminated_) {
return false;
}
task_queue_->RegisterTask(internal_queue_id_, std::move(task), target_time,
task_source_grade, instant_task_hint);
return true;
}
void MessageLoopImpl::AddTaskObserver(intptr_t key, base::closure callback) {
if (callback != nullptr) {
task_queue_->AddTaskObserver(internal_queue_id_, key, std::move(callback));
} else {
}
}
void MessageLoopImpl::RemoveTaskObserver(intptr_t key) {
task_queue_->RemoveTaskObserver(internal_queue_id_, key);
}
void MessageLoopImpl::DoRun() {
if (terminated_) {
return;
}
Run();
terminated_ = true;
RunExpiredTasksNow();
task_queue_->DisposeTasks(internal_queue_id_);
}
void MessageLoopImpl::DoTerminate() {
terminated_ = true;
Terminate();
}
void MessageLoopImpl::FlushTasks(FlushType type) {
BASE_TRACE_EVENT(LYNX_BASE_TRACE_CATEGORY, MESSAGE_LOOP_FLUSH_TASK);
if (FlushTasksWithRestrictionDuration(
type, queue_ids_, restriction_duration_.ToMilliseconds())) {
task_queue_->WakeUp(queue_ids_);
}
}
void MessageLoopImpl::FlushVSyncAlignedTasks(FlushType type) {
BASE_TRACE_EVENT(LYNX_BASE_TRACE_CATEGORY,
MESSAGE_LOOP_FLUSH_VASYNC_ALIGNED_TASKS);
FlushTasksWithRestrictionDuration(type, vsync_aligned_task_queue_ids_,
max_execute_time_ms_);
}
bool MessageLoopImpl::FlushTasksWithRestrictionDuration(
FlushType type, const std::vector<TaskQueueId>& queue_ids,
int64_t restriction_duration) {
if (queue_ids.empty()) {
return false;
}
std::vector<const base::closure*> observers;
const auto now = fml::TimePoint::Now();
if (restriction_duration == fml::TimeDelta::Max().ToMilliseconds()) {
do {
auto invocation =
task_queue_->GetNextTaskToRun(queue_ids, now, &observers);
if (!invocation) {
break;
}
invocation();
if (!observers.empty()) {
for (const auto& observer : observers) {
(*observer)();
}
observers.clear();
}
if (type == FlushType::kSingle) {
break;
}
} while (true);
return false;
} else {
bool reach_max_restriction = false;
do {
auto invocation =
task_queue_->GetNextTaskToRun(queue_ids, now, &observers);
if (!invocation) {
break;
}
invocation();
if (!observers.empty()) {
for (const auto& observer : observers) {
(*observer)();
}
observers.clear();
}
if (type == FlushType::kSingle) {
break;
}
if (restriction_duration <=
(fml::TimePoint::Now() - now).ToMilliseconds()) {
reach_max_restriction = true;
break;
}
} while (true);
return reach_max_restriction;
}
}
void MessageLoopImpl::WakeUp(fml::TimePoint time_point,
bool is_woken_by_vsync) {
if (is_woken_by_vsync && vsync_request_) {
WakeUpByVSync(time_point);
return;
}
WakeUp(time_point);
}
void MessageLoopImpl::WakeUpByVSync(fml::TimePoint time_point) {
if (fml::TimePoint::Now() < time_point || WaitForVSyncTimeOut()) {
WakeUp(time_point);
} else if (!HasPendingVSyncRequest()) {
request_vsync_time_millis_ = base::CurrentSystemTimeMilliseconds();
vsync_request_([this](int64_t frame_start_time_ns,
int64_t frame_target_time_ns) {
request_vsync_time_millis_ = 0;
max_execute_time_ms_ =
static_cast<int64_t>((frame_target_time_ns - frame_start_time_ns) *
kTraversalProportion / kNSecPerMSec);
FlushVSyncAlignedTasks(FlushType::kAll);
});
}
}
bool MessageLoopImpl::WaitForVSyncTimeOut() {
auto now = base::CurrentSystemTimeMilliseconds();
return HasPendingVSyncRequest() &&
(now - request_vsync_time_millis_ >= kWaitingVSyncTimeoutMillis);
}
bool MessageLoopImpl::HasPendingVSyncRequest() {
return request_vsync_time_millis_ > 0;
}
void MessageLoopImpl::RunExpiredTasksNow() { FlushTasks(FlushType::kAll); }
void MessageLoopImpl::RunSingleExpiredTaskNow() {
FlushTasks(FlushType::kSingle);
}
TaskQueueId MessageLoopImpl::GetTaskQueueId() const {
return internal_queue_id_;
}
std::vector<TaskQueueId> MessageLoopImpl::GetTaskQueueIds() const {
return queue_ids_;
}
void MessageLoopImpl::Bind(const TaskQueueId& queue_id,
bool should_run_expired_tasks_immediately) {
BASE_TRACE_EVENT(LYNX_BASE_TRACE_CATEGORY, MESSAGE_LOOP_IMPL_BIND);
auto& ids_vec =
(vsync_request_ && task_queue_->IsTaskQueueAlignedWithVSync(queue_id))
? vsync_aligned_task_queue_ids_
: queue_ids_;
bool found = false;
for (const auto& exist : ids_vec) {
if (exist == queue_id) {
found = true;
break;
}
}
if (!found) {
ids_vec.emplace_back(queue_id);
}
task_queue_->SetWakeable(queue_id, this);
if (should_run_expired_tasks_immediately) {
FlushTasksWithRestrictionDuration(FlushType::kAll, {queue_id},
fml::TimeDelta::Max().ToMilliseconds());
}
}
void MessageLoopImpl::UnBind(const TaskQueueId& queue_id) {
auto& ids =
(vsync_request_ && task_queue_->IsTaskQueueAlignedWithVSync(queue_id))
? vsync_aligned_task_queue_ids_
: queue_ids_;
for (auto it = ids.begin(); it != ids.end(); ++it) {
if (*it == queue_id) {
ids.erase(it);
task_queue_->SetWakeable(queue_id, nullptr);
break;
}
}
}
void MessageLoopImpl::SetRestrictionDuration(fml::TimeDelta duration) {
restriction_duration_ = duration;
}
void MessageLoopImpl::SetVSyncRequest(VSyncRequest vsync_request) {
vsync_request_ = std::move(vsync_request);
}
bool MessageLoopImpl::CanRunNow() {
return MessageLoop::GetCurrent().GetLoopImpl().get() == this;
}
}
}