| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/renderer_host/frame_token_message_queue.h" |
| |
| #include "base/bind.h" |
| #include "base/debug/crash_logging.h" |
| #include "base/debug/dump_without_crashing.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "ipc/ipc_message.h" |
| |
| namespace content { |
| |
| FrameTokenMessageQueue::FrameTokenMessageQueue() = default; |
| |
| FrameTokenMessageQueue::~FrameTokenMessageQueue() = default; |
| |
| void FrameTokenMessageQueue::Init(Client* client) { |
| client_ = client; |
| } |
| |
| void FrameTokenMessageQueue::DidProcessFrame(uint32_t frame_token) { |
| // Frame tokens always increase. |
| if (frame_token <= last_received_frame_token_) { |
| // TODO(samans): Remove this once the investigation into |
| // https://crbug.com/1045372 is over. |
| static auto* last_frame_token = base::debug::AllocateCrashKeyString( |
| "last_frame_token", base::debug::CrashKeySize::Size32); |
| static auto* new_frame_token = base::debug::AllocateCrashKeyString( |
| "new_frame_token", base::debug::CrashKeySize::Size32); |
| base::debug::SetCrashKeyString( |
| last_frame_token, base::NumberToString(last_received_frame_token_)); |
| base::debug::SetCrashKeyString(new_frame_token, |
| base::NumberToString(frame_token)); |
| base::debug::DumpWithoutCrashing(); |
| |
| client_->OnInvalidFrameToken(frame_token); |
| return; |
| } |
| |
| last_received_frame_token_ = frame_token; |
| |
| // Gets the first callback associated with a token after |frame_token| or |
| // callback_map_.end(). |
| auto upper_bound = callback_map_.upper_bound(frame_token); |
| |
| // std::multimap already sorts on keys, so this will process all enqueued |
| // messages up to the current frame token. |
| for (auto it = callback_map_.begin(); it != upper_bound; ++it) |
| std::move(it->second).Run(); |
| |
| // Clear all callbacks up to the current frame token. |
| callback_map_.erase(callback_map_.begin(), upper_bound); |
| } |
| |
| void FrameTokenMessageQueue::EnqueueOrRunFrameTokenCallback( |
| uint32_t frame_token, |
| base::OnceClosure callback) { |
| // Zero token is invalid. |
| if (!frame_token) { |
| client_->OnInvalidFrameToken(frame_token); |
| return; |
| } |
| |
| if (frame_token <= last_received_frame_token_) { |
| std::move(callback).Run(); |
| return; |
| } |
| callback_map_.insert(std::make_pair(frame_token, std::move(callback))); |
| } |
| |
| void FrameTokenMessageQueue::OnFrameSwapMessagesReceived( |
| uint32_t frame_token, |
| std::vector<IPC::Message> messages) { |
| // TODO(samans): Remove this once the investigation into |
| // https://crbug.com/1045372 is over. |
| if (!frame_token) { |
| base::debug::DumpWithoutCrashing(); |
| } |
| EnqueueOrRunFrameTokenCallback( |
| frame_token, base::BindOnce(&FrameTokenMessageQueue::ProcessSwapMessages, |
| base::Unretained(this), std::move(messages))); |
| } |
| |
| void FrameTokenMessageQueue::Reset() { |
| last_received_frame_token_ = 0; |
| callback_map_.clear(); |
| } |
| |
| void FrameTokenMessageQueue::ProcessSwapMessages( |
| std::vector<IPC::Message> messages) { |
| for (const IPC::Message& i : messages) { |
| client_->OnProcessSwapMessage(i); |
| if (i.dispatch_error()) |
| client_->OnMessageDispatchError(i); |
| } |
| } |
| |
| } // namespace content |