blob: 3c666430fed124fe0f7fc0659c45df5e146f97ce [file] [log] [blame]
// Copyright 2021 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 "chrome/browser/ash/crosapi/crosapi_manager.h"
#include <utility>
#include "base/bind.h"
#include "base/check.h"
#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "chrome/browser/ash/crosapi/browser_service_host_ash.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
namespace crosapi {
namespace {
CrosapiManager* g_instance = nullptr;
} // namespace
// Handles a flow to invite crosapi client (such as lacros-chrome) to Mojo
// universe.
// - Bind the given end point to BrowserService.
// - Queuing another IPC to call RequestCrosapiReceiver to obtain the
// pending_receiver from the client.
// - Then, send the invitation to crosapi.
// - On Crosapi receiver is arrived, it is bound to CrosapiAsh, then
// query BrowserService version.
// - Finally, on version of BrowserService got available, completion_callback is
// invoked.
class CrosapiManager::LegacyInvitationFlow {
public:
LegacyInvitationFlow(CrosapiId crosapi_id,
base::OnceClosure disconnect_handler)
: crosapi_id_(crosapi_id),
disconnect_handler_(std::move(disconnect_handler)) {}
LegacyInvitationFlow(const LegacyInvitationFlow&) = delete;
LegacyInvitationFlow& operator=(const LegacyInvitationFlow&) = delete;
~LegacyInvitationFlow() = default;
void Run(mojo::PlatformChannelEndpoint local_endpoint) {
mojo::OutgoingInvitation invitation;
browser_service_.Bind(mojo::PendingRemote<crosapi::mojom::BrowserService>(
invitation.AttachMessagePipe(/*token=*/0), /*version=*/0));
browser_service_.set_disconnect_handler(base::BindOnce(
&LegacyInvitationFlow::OnDisconnected, weak_factory_.GetWeakPtr()));
browser_service_->RequestCrosapiReceiver(
base::BindOnce(&LegacyInvitationFlow::OnCrosapiReceiverReceived,
weak_factory_.GetWeakPtr()));
mojo::OutgoingInvitation::Send(std::move(invitation),
base::kNullProcessHandle,
std::move(local_endpoint));
}
private:
void OnDisconnected() {
// Preserve the callback before destroying itself.
auto disconnect_handler = std::move(disconnect_handler_);
OnComplete(); // |this| is deleted here.
if (!disconnect_handler.is_null())
std::move(disconnect_handler).Run();
}
void OnCrosapiReceiverReceived(
mojo::PendingReceiver<crosapi::mojom::Crosapi> pending_receiver) {
// Preserve needed members before destroying itself.
auto browser_service = std::move(browser_service_);
auto crosapi_id = crosapi_id_;
auto disconnect_handler = std::move(disconnect_handler_);
OnComplete(); // |this| is deleted here.
auto* crosapi_manager = CrosapiManager::Get();
crosapi_manager->crosapi_ash_->BindReceiver(
std::move(pending_receiver), crosapi_id, std::move(disconnect_handler));
crosapi_manager->crosapi_ash_->browser_service_host_ash()->AddRemote(
crosapi_id, std::move(browser_service));
}
void OnComplete() {
auto* crosapi_manager = CrosapiManager::Get();
base::EraseIf(crosapi_manager->pending_invitation_flow_list_,
[this](const std::unique_ptr<LegacyInvitationFlow>& ptr) {
return ptr.get() == this;
});
}
mojo::Remote<crosapi::mojom::BrowserService> browser_service_;
CrosapiId crosapi_id_;
base::OnceClosure disconnect_handler_;
base::WeakPtrFactory<LegacyInvitationFlow> weak_factory_{this};
};
bool CrosapiManager::IsInitialized() {
return g_instance != nullptr;
}
CrosapiManager* CrosapiManager::Get() {
DCHECK(g_instance);
return g_instance;
}
CrosapiManager::CrosapiManager()
: crosapi_ash_(std::make_unique<CrosapiAsh>()) {
DCHECK(!g_instance);
g_instance = this;
}
CrosapiManager::~CrosapiManager() {
DCHECK(g_instance == this);
g_instance = nullptr;
}
CrosapiId CrosapiManager::SendInvitation(
mojo::PlatformChannelEndpoint local_endpoint,
base::OnceClosure disconnect_handler) {
CrosapiId crosapi_id = crosapi_id_generator_.GenerateNextId();
mojo::OutgoingInvitation invitation;
crosapi_ash_->BindReceiver(mojo::PendingReceiver<crosapi::mojom::Crosapi>(
invitation.AttachMessagePipe(/*token=*/0)),
crosapi_id, std::move(disconnect_handler));
mojo::OutgoingInvitation::Send(std::move(invitation),
base::kNullProcessHandle,
std::move(local_endpoint));
return crosapi_id;
}
CrosapiId CrosapiManager::SendLegacyInvitation(
mojo::PlatformChannelEndpoint local_endpoint,
base::OnceClosure disconnect_handler) {
CrosapiId crosapi_id = crosapi_id_generator_.GenerateNextId();
pending_invitation_flow_list_.push_back(
std::make_unique<LegacyInvitationFlow>(crosapi_id,
std::move(disconnect_handler)));
pending_invitation_flow_list_.back()->Run(std::move(local_endpoint));
return crosapi_id;
}
} // namespace crosapi