mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2022 The Chromium Embedded Framework 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 "tests/cefclient/renderer/ipc_performance_test.h"
 | |
| 
 | |
| #include "include/cef_shared_process_message_builder.h"
 | |
| #include "include/wrapper/cef_helpers.h"
 | |
| #include "tests/shared/common/binary_value_utils.h"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // JS object member names.
 | |
| constexpr char kMessageSize[] = "size";
 | |
| constexpr char kTestId[] = "testId";
 | |
| constexpr CefV8Value::PropertyAttribute kAttributes =
 | |
|     static_cast<CefV8Value::PropertyAttribute>(
 | |
|         V8_PROPERTY_ATTRIBUTE_READONLY | V8_PROPERTY_ATTRIBUTE_DONTENUM |
 | |
|         V8_PROPERTY_ATTRIBUTE_DONTDELETE);
 | |
| 
 | |
| struct TestInfo {
 | |
|   size_t message_size = 0;
 | |
|   int id = 0;
 | |
|   bool is_valid = false;
 | |
| };
 | |
| 
 | |
| TestInfo GetTest(const CefV8ValueList& arguments, CefString& exception) {
 | |
|   TestInfo info{};
 | |
| 
 | |
|   if (arguments.size() != 1 || !arguments[0]->IsObject()) {
 | |
|     exception = "Invalid arguments; expecting a single object";
 | |
|     return info;
 | |
|   }
 | |
| 
 | |
|   CefRefPtr<CefV8Value> arg = arguments[0];
 | |
|   CefRefPtr<CefV8Value> message_size = arg->GetValue(kMessageSize);
 | |
|   if (!message_size.get() || !message_size->IsInt()) {
 | |
|     exception =
 | |
|         "Invalid arguments; object member 'size' is required and must have "
 | |
|         "integer type";
 | |
|     return info;
 | |
|   }
 | |
| 
 | |
|   if (message_size->GetIntValue() < 1) {
 | |
|     exception =
 | |
|         "Invalid arguments; object member 'size' must be "
 | |
|         "positive";
 | |
|     return info;
 | |
|   }
 | |
| 
 | |
|   CefRefPtr<CefV8Value> test_id = arg->GetValue(kTestId);
 | |
|   if (!message_size.get() || !message_size->IsInt()) {
 | |
|     exception =
 | |
|         "Invalid arguments; object member 'testId' is required and must "
 | |
|         "have integer type";
 | |
|     return info;
 | |
|   }
 | |
| 
 | |
|   info.message_size = static_cast<size_t>(message_size->GetIntValue());
 | |
|   info.id = test_id->GetIntValue();
 | |
|   info.is_valid = true;
 | |
| 
 | |
|   return info;
 | |
| }
 | |
| 
 | |
| // Handle bindings in the render process.
 | |
| class IpcDelegate final : public client::ClientAppRenderer::Delegate {
 | |
|  public:
 | |
|   class V8HandlerImpl final : public CefV8Handler {
 | |
|    public:
 | |
|     explicit V8HandlerImpl(const CefRefPtr<IpcDelegate>& delegate)
 | |
|         : delegate_(delegate) {}
 | |
|     V8HandlerImpl(const V8HandlerImpl&) = delete;
 | |
|     V8HandlerImpl& operator=(const V8HandlerImpl&) = delete;
 | |
| 
 | |
|     bool Execute(const CefString& name,
 | |
|                  CefRefPtr<CefV8Value> object,
 | |
|                  const CefV8ValueList& arguments,
 | |
|                  CefRefPtr<CefV8Value>& retval,
 | |
|                  CefString& exception) override {
 | |
|       if (name == bv_utils::kTestSendProcessMessage) {
 | |
|         const auto test = GetTest(arguments, exception);
 | |
|         if (test.is_valid) {
 | |
|           SendTestProcessMessage(test.message_size, test.id);
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
| 
 | |
|       if (name == bv_utils::kTestSendSMRProcessMessage) {
 | |
|         const auto test = GetTest(arguments, exception);
 | |
|         if (test.is_valid) {
 | |
|           SendTestSMRProcessMessage(test.message_size, test.id);
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
| 
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|    private:
 | |
|     void SendTestProcessMessage(size_t message_size, int test_id) {
 | |
|       auto context = CefV8Context::GetCurrentContext();
 | |
|       delegate_->SendTestProcessMessage(context->GetFrame(), message_size,
 | |
|                                         test_id);
 | |
|     }
 | |
| 
 | |
|     void SendTestSMRProcessMessage(size_t message_size, int test_id) {
 | |
|       auto context = CefV8Context::GetCurrentContext();
 | |
|       delegate_->SendTestSMRProcessMessage(context->GetFrame(), message_size,
 | |
|                                            test_id);
 | |
|     }
 | |
| 
 | |
|     CefRefPtr<IpcDelegate> delegate_;
 | |
|     IMPLEMENT_REFCOUNTING(V8HandlerImpl);
 | |
|   };
 | |
| 
 | |
|   IpcDelegate() = default;
 | |
|   IpcDelegate(const IpcDelegate&) = delete;
 | |
|   IpcDelegate& operator=(const IpcDelegate&) = delete;
 | |
| 
 | |
|   void OnContextCreated(CefRefPtr<client::ClientAppRenderer> app,
 | |
|                         CefRefPtr<CefBrowser> browser,
 | |
|                         CefRefPtr<CefFrame> frame,
 | |
|                         CefRefPtr<CefV8Context> context) override {
 | |
|     CEF_REQUIRE_RENDERER_THREAD();
 | |
| 
 | |
|     CefRefPtr<CefV8Handler> handler = new V8HandlerImpl(this);
 | |
| 
 | |
|     // Register function handlers with the 'window' object.
 | |
|     auto window = context->GetGlobal();
 | |
|     window->SetValue(
 | |
|         bv_utils::kTestSendProcessMessage,
 | |
|         CefV8Value::CreateFunction(bv_utils::kTestSendProcessMessage, handler),
 | |
|         kAttributes);
 | |
| 
 | |
|     window->SetValue(bv_utils::kTestSendSMRProcessMessage,
 | |
|                      CefV8Value::CreateFunction(
 | |
|                          bv_utils::kTestSendSMRProcessMessage, handler),
 | |
|                      kAttributes);
 | |
|   }
 | |
| 
 | |
|   bool OnProcessMessageReceived(CefRefPtr<client::ClientAppRenderer> app,
 | |
|                                 CefRefPtr<CefBrowser> browser,
 | |
|                                 CefRefPtr<CefFrame> frame,
 | |
|                                 CefProcessId source_process,
 | |
|                                 CefRefPtr<CefProcessMessage> message) override {
 | |
|     CEF_REQUIRE_RENDERER_THREAD();
 | |
|     const auto finish_time = bv_utils::Now();
 | |
| 
 | |
|     if (message->GetName() == bv_utils::kTestSendProcessMessage) {
 | |
|       auto args = message->GetArgumentList();
 | |
|       DCHECK_EQ(args->GetSize(), 1U);
 | |
| 
 | |
|       const auto browser_msg =
 | |
|           bv_utils::GetBrowserMsgFromBinary(args->GetBinary(0));
 | |
|       PassTestResultToJs(frame, finish_time, browser_msg);
 | |
| 
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     if (message->GetName() == bv_utils::kTestSendSMRProcessMessage) {
 | |
|       const auto region = message->GetSharedMemoryRegion();
 | |
|       DCHECK(region->IsValid());
 | |
|       DCHECK_GE(region->Size(), sizeof(bv_utils::BrowserMessage));
 | |
| 
 | |
|       const auto browser_msg =
 | |
|           static_cast<const bv_utils::BrowserMessage*>(region->Memory());
 | |
| 
 | |
|       PassTestResultToJs(frame, finish_time, *browser_msg);
 | |
| 
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   IMPLEMENT_REFCOUNTING(IpcDelegate);
 | |
| 
 | |
|   void SendTestProcessMessage(CefRefPtr<CefFrame> frame,
 | |
|                               size_t message_size,
 | |
|                               int test_id) {
 | |
|     CEF_REQUIRE_RENDERER_THREAD();
 | |
| 
 | |
|     auto process_message =
 | |
|         CefProcessMessage::Create(bv_utils::kTestSendProcessMessage);
 | |
|     auto args = process_message->GetArgumentList();
 | |
| 
 | |
|     const auto buffer_size =
 | |
|         std::max(message_size, sizeof(bv_utils::RendererMessage));
 | |
|     std::vector<uint8_t> buffer(buffer_size);
 | |
| 
 | |
|     const auto renderer_msg =
 | |
|         reinterpret_cast<bv_utils::RendererMessage*>(buffer.data());
 | |
| 
 | |
|     renderer_msg->test_id = test_id;
 | |
|     renderer_msg->start_time = bv_utils::Now();
 | |
| 
 | |
|     args->SetBinary(0, bv_utils::CreateCefBinaryValue(buffer));
 | |
|     frame->SendProcessMessage(PID_BROWSER, process_message);
 | |
|   }
 | |
| 
 | |
|   void SendTestSMRProcessMessage(CefRefPtr<CefFrame> frame,
 | |
|                                  size_t message_size,
 | |
|                                  int test_id) {
 | |
|     CEF_REQUIRE_RENDERER_THREAD();
 | |
| 
 | |
|     const auto buffer_size =
 | |
|         std::max(message_size, sizeof(bv_utils::RendererMessage));
 | |
| 
 | |
|     std::vector<uint8_t> buffer(buffer_size);
 | |
|     const auto renderer_msg =
 | |
|         reinterpret_cast<bv_utils::RendererMessage*>(buffer.data());
 | |
|     renderer_msg->test_id = test_id;
 | |
|     renderer_msg->start_time = bv_utils::Now();
 | |
| 
 | |
|     auto builder = CefSharedProcessMessageBuilder::Create(
 | |
|         bv_utils::kTestSendSMRProcessMessage, buffer_size);
 | |
| 
 | |
|     bv_utils::CopyDataIntoMemory(buffer, builder->Memory());
 | |
| 
 | |
|     frame->SendProcessMessage(PID_BROWSER, builder->Build());
 | |
|   }
 | |
| 
 | |
|   // Execute the onSuccess JavaScript callback.
 | |
|   void PassTestResultToJs(CefRefPtr<CefFrame> frame,
 | |
|                           const bv_utils::TimePoint& finish_time,
 | |
|                           const bv_utils::BrowserMessage& msg) {
 | |
|     const auto rendered_to_browser = msg.duration;
 | |
|     const auto browser_to_rendered = finish_time - msg.start_time;
 | |
| 
 | |
|     CefString code = "testSendProcessMessageResult(" +
 | |
|                      std::to_string(msg.test_id) + ", " +
 | |
|                      bv_utils::ToMicroSecString(rendered_to_browser) + ", " +
 | |
|                      bv_utils::ToMicroSecString(browser_to_rendered) + ");";
 | |
| 
 | |
|     frame->ExecuteJavaScript(code, frame->GetURL(), 0);
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| namespace client::ipc_performance_test {
 | |
| 
 | |
| void CreateDelegates(ClientAppRenderer::DelegateSet& delegates) {
 | |
|   delegates.insert(new IpcDelegate());
 | |
| }
 | |
| 
 | |
| }  // namespace client::ipc_performance_test
 |