1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/task/sequence_manager/task_queue.h"
#include "codelabs/mojo_examples/mojo_impls.h"
#include "codelabs/mojo_examples/mojom/interface.mojom.h"
#include "codelabs/mojo_examples/process_bootstrapper.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
static ObjectAImpl g_object_a;
static ObjectBImpl g_object_b;
class ProcessImpl : public codelabs::mojom::Process {
public:
ProcessImpl(mojo::PendingReceiver<codelabs::mojom::Process> pending_receiver,
scoped_refptr<base::SingleThreadTaskRunner> freezable_tq_runner) {
receiver_.Bind(std::move(pending_receiver));
freezable_tq_runner_ = std::move(freezable_tq_runner);
}
private:
// codelabs::mojo::Process
void SayHello() override {
LOG(INFO) << "Hello! (invoked in the renderer, from the browser)";
}
void GetAssociatedInterface(
const std::string& name,
mojo::PendingAssociatedReceiver<codelabs::mojom::GenericInterface>
receiver) override {
LOG(INFO) << "Renderer: GetAssociatedInterface() for " << name;
if (name == "ObjectA") {
mojo::PendingAssociatedReceiver<codelabs::mojom::ObjectA> pending_a(
receiver.PassHandle());
g_object_a.BindToFrozenTaskRunner(std::move(pending_a),
std::move(freezable_tq_runner_));
} else if (name == "ObjectB") {
mojo::PendingAssociatedReceiver<codelabs::mojom::ObjectB> pending_b(
receiver.PassHandle());
g_object_b.Bind(std::move(pending_b));
}
}
mojo::Receiver<codelabs::mojom::Process> receiver_{this};
// This is a freezable task runner that only `g_object_a` gets bound to.
scoped_refptr<base::SingleThreadTaskRunner> freezable_tq_runner_;
};
static std::unique_ptr<ProcessImpl> g_process_impl;
class CustomTaskQueue : public base::RefCounted<CustomTaskQueue> {
public:
CustomTaskQueue(base::sequence_manager::SequenceManager& sequence_manager,
const base::sequence_manager::TaskQueue::Spec& spec)
: task_queue_(sequence_manager.CreateTaskQueue(spec)),
voter_(task_queue_->CreateQueueEnabledVoter()) {}
void FreezeTaskQueue() { voter_->SetVoteToEnable(false); }
void UnfreezeTaskQueue() {
LOG(INFO) << "Unfreezing the task queue that `ObjectAImpl` is bound to.";
voter_->SetVoteToEnable(true);
}
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() const {
return task_queue_->task_runner();
}
private:
~CustomTaskQueue() = default;
friend class base::RefCounted<CustomTaskQueue>;
base::sequence_manager::TaskQueue::Handle task_queue_;
// Used to enable/disable the underlying `TaskQueueImpl`.
std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter> voter_;
};
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
LOG(INFO) << "Renderer: "
<< base::CommandLine::ForCurrentProcess()->GetCommandLineString();
// Set up the scheduling infrastructure for this process. It consists of:
// 1.) A SequenceManager that is bound to the current thread (main thread)
// 2.) A default task queue
// 3.) A `CustomTaskQueue` that is easily freezable and unfreezable. This
// part is specific to this example.
ProcessBootstrapper bootstrapper;
bootstrapper.InitMainThread(base::MessagePumpType::IO);
bootstrapper.InitMojo(/*as_browser_process=*/false);
scoped_refptr<CustomTaskQueue> freezable_tq =
base::MakeRefCounted<CustomTaskQueue>(
*bootstrapper.sequence_manager.get(),
base::sequence_manager::TaskQueue::Spec(
base::sequence_manager::QueueName::TEST_TQ));
freezable_tq->FreezeTaskQueue();
// Accept an invitation.
mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept(
mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
*base::CommandLine::ForCurrentProcess()));
mojo::ScopedMessagePipeHandle pipe = invitation.ExtractMessagePipe("pipe");
base::RunLoop run_loop;
// Post a task that will run in 3 seconds, that will unfreeze the custom task
// queue to which the `codelabs::mojom::ObjectA` object is bound to.
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
[](scoped_refptr<CustomTaskQueue> freezable_tq) {
freezable_tq->UnfreezeTaskQueue();
},
freezable_tq),
base::Seconds(3));
// Create a process-wide receiver that will broker connects to the backing
// `codelabs::mojom::ObjectA` and `codelabs::mojom::ObjectB` implementations.
mojo::PendingReceiver<codelabs::mojom::Process> pending_receiver(
std::move(pipe));
g_process_impl = std::make_unique<ProcessImpl>(std::move(pending_receiver),
freezable_tq->task_runner());
run_loop.Run();
return 0;
}
|