blob: d03d6958defecad078e6d4ea88bbae3826c98387 [file] [log] [blame]
// Copyright 2017 The Chromium OS 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 "midis/client_tracker.h"
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <memory>
#include <string>
#include <utility>
#include <base/bind.h>
#include <base/location.h>
#include <brillo/message_loops/message_loop.h>
#include <mojo/edk/embedder/embedder.h>
#include <mojo/public/cpp/bindings/binding.h>
namespace {
constexpr char kMidisPipe[] = "arc-midis-pipe";
// Implementation of the MidisHost interface. This is used to
// get the actual MidisManager interface which is used by the client to
// communicate with midis.
// A request to initialize this should be initiated by the ArcBridgeHost.
//
// NOTE: It is expected that this class should only be instantiated once
// during the lifetime of the service. An error in the Message Pipe associated
// with this class is most likely an unrecoverable error, and will necessitate
// the restart of the midis service from Chrome.
class MidisHostImpl : public arc::mojom::MidisHost {
public:
// |client_tracker|, which must outlive MidisHostImpl, is owned by the caller.
MidisHostImpl(arc::mojom::MidisHostRequest request,
midis::ClientTracker* client_tracker);
~MidisHostImpl() override = default;
// mojom::MidisHost:
void Connect(arc::mojom::MidisServerRequest request,
arc::mojom::MidisClientPtr client_ptr) override;
private:
// It's safe to hold a raw pointer to ClientTracker since we can assume
// that the lifecycle of ClientTracker is a superset of the lifecycle of
// MidisHostImpl.
midis::ClientTracker* client_tracker_;
mojo::Binding<arc::mojom::MidisHost> binding_;
DISALLOW_COPY_AND_ASSIGN(MidisHostImpl);
};
MidisHostImpl::MidisHostImpl(arc::mojom::MidisHostRequest request,
midis::ClientTracker* client_tracker)
: client_tracker_(client_tracker), binding_(this, std::move(request)) {}
void MidisHostImpl::Connect(arc::mojom::MidisServerRequest request,
arc::mojom::MidisClientPtr client_ptr) {
VLOG(1) << "Connect() called.";
client_tracker_->MakeMojoClient(std::move(request), std::move(client_ptr));
}
} // namespace
namespace midis {
void ClientTracker::MakeMojoClient(arc::mojom::MidisServerRequest request,
arc::mojom::MidisClientPtr client_ptr) {
client_id_counter_++;
VLOG(1) << "MakeMojoClient called.";
auto new_cli = std::make_unique<Client>(
device_tracker_,
client_id_counter_,
base::Bind(&ClientTracker::RemoveClient, weak_factory_.GetWeakPtr()),
std::move(request),
std::move(client_ptr));
if (new_cli) {
clients_.emplace(client_id_counter_, std::move(new_cli));
}
}
ClientTracker::ClientTracker() : client_id_counter_(0), weak_factory_(this) {}
ClientTracker::~ClientTracker() {
for (auto& client : clients_) {
device_tracker_->RemoveClientFromDevices(client.first);
}
clients_.clear();
}
void ClientTracker::InitClientTracker() {
VLOG(1) << "Start client Mojo server.";
mojo::edk::Init();
mojo::edk::InitIPCSupport(this, base::ThreadTaskRunnerHandle::Get());
}
void ClientTracker::RemoveClient(uint32_t client_id) {
// First delete all references to this device.
device_tracker_->RemoveClientFromDevices(client_id);
clients_.erase(client_id);
}
void ClientTracker::AcceptProxyConnection(base::ScopedFD fd) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
mojo::edk::SetParentPipeHandle(
mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release())));
mojo::ScopedMessagePipeHandle child_pipe =
mojo::edk::CreateChildMessagePipe(kMidisPipe);
midis_host_ = std::make_unique<MidisHostImpl>(
mojo::MakeRequest<arc::mojom::MidisHost>(std::move(child_pipe)), this);
}
bool ClientTracker::IsProxyConnected() {
return midis_host_ != nullptr;
}
void ClientTracker::OnShutdownComplete() {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
mojo::edk::ShutdownIPCSupport();
}
} // namespace midis