blob: 2dcfdbe4b3dd4f9b034406b15854cd5795788095 [file] [log] [blame]
// Copyright 2016 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 "services/catalog/catalog.h"
#include <string>
#include <utility>
#include <vector>
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/path_service.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "components/services/filesystem/directory_impl.h"
#include "components/services/filesystem/lock_table.h"
#include "components/services/filesystem/public/interfaces/types.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace catalog {
namespace {
using Manifest = service_manager::Manifest;
std::map<Manifest::ServiceName, const Manifest*> CreateManifestMap(
const std::vector<Manifest>& manifests) {
std::map<Manifest::ServiceName, const Manifest*> map;
for (const auto& manifest : manifests) {
map[manifest.service_name] = &manifest;
for (const auto& entry : CreateManifestMap(manifest.packaged_services))
map[entry.first] = entry.second;
}
return map;
}
std::map<Manifest::ServiceName, const Manifest*> CreateParentManifestMap(
const std::vector<Manifest>& manifests) {
std::map<Manifest::ServiceName, const Manifest*> map;
for (const auto& parent : manifests) {
for (const auto& child : parent.packaged_services)
map[child.service_name] = &parent;
for (const auto& entry : CreateParentManifestMap(parent.packaged_services))
map[entry.first] = entry.second;
}
return map;
}
} // namespace
// Wraps state needed for servicing directory requests on a separate thread.
// filesystem::LockTable is not thread safe, so it's wrapped in
// DirectoryThreadState.
class Catalog::DirectoryThreadState
: public base::RefCountedDeleteOnSequence<DirectoryThreadState> {
public:
explicit DirectoryThreadState(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: base::RefCountedDeleteOnSequence<DirectoryThreadState>(
std::move(task_runner)) {}
scoped_refptr<filesystem::LockTable> lock_table() {
if (!lock_table_)
lock_table_ = new filesystem::LockTable;
return lock_table_;
}
private:
friend class base::DeleteHelper<DirectoryThreadState>;
friend class base::RefCountedDeleteOnSequence<DirectoryThreadState>;
~DirectoryThreadState() = default;
scoped_refptr<filesystem::LockTable> lock_table_;
DISALLOW_COPY_AND_ASSIGN(DirectoryThreadState);
};
Catalog::Catalog(const std::vector<Manifest>& manifests)
: manifests_(manifests),
manifest_map_(CreateManifestMap(manifests_)),
parent_manifest_map_(CreateParentManifestMap(manifests_)) {
registry_.AddInterface<mojom::Catalog>(base::BindRepeating(
&Catalog::BindCatalogRequest, base::Unretained(this)));
registry_.AddInterface<filesystem::mojom::Directory>(base::BindRepeating(
&Catalog::BindDirectoryRequest, base::Unretained(this)));
}
Catalog::~Catalog() = default;
void Catalog::BindServiceRequest(
service_manager::mojom::ServiceRequest request) {
service_binding_.Bind(std::move(request));
}
const service_manager::Manifest* Catalog::GetManifest(
const Manifest::ServiceName& service_name) {
const auto it = manifest_map_.find(service_name);
if (it == manifest_map_.end())
return nullptr;
return it->second;
}
const service_manager::Manifest* Catalog::GetParentManifest(
const Manifest::ServiceName& service_name) {
auto it = parent_manifest_map_.find(service_name);
if (it == parent_manifest_map_.end())
return nullptr;
return it->second;
}
void Catalog::BindCatalogRequest(mojom::CatalogRequest request) {
catalog_bindings_.AddBinding(this, std::move(request));
}
void Catalog::BindDirectoryRequest(
filesystem::mojom::DirectoryRequest request) {
if (!directory_task_runner_) {
directory_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(),
// Use USER_BLOCKING as this gates showing UI during startup.
base::TaskPriority::USER_BLOCKING,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
directory_thread_state_ = new DirectoryThreadState(directory_task_runner_);
}
directory_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&Catalog::BindDirectoryRequestOnBackgroundThread,
directory_thread_state_, std::move(request)));
}
// static
void Catalog::BindDirectoryRequestOnBackgroundThread(
scoped_refptr<DirectoryThreadState> thread_state,
filesystem::mojom::DirectoryRequest request) {
base::FilePath resources_path;
base::PathService::Get(base::DIR_MODULE, &resources_path);
mojo::MakeStrongBinding(
std::make_unique<filesystem::DirectoryImpl>(
resources_path, scoped_refptr<filesystem::SharedTempDir>(),
thread_state->lock_table()),
std::move(request));
}
void Catalog::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void Catalog::GetEntries(const base::Optional<std::vector<std::string>>& names,
GetEntriesCallback callback) {
std::vector<mojom::EntryPtr> entries;
if (!names.has_value()) {
for (const auto& entry : manifest_map_) {
const auto* manifest = entry.second;
entries.push_back(mojom::Entry::New(manifest->service_name,
manifest->display_name.raw_string));
}
} else {
for (const std::string& name : names.value()) {
const auto* manifest = GetManifest(name);
if (manifest) {
entries.push_back(mojom::Entry::New(manifest->service_name,
manifest->display_name.raw_string));
}
}
}
std::move(callback).Run(std::move(entries));
}
void Catalog::GetEntriesProvidingCapability(
const std::string& capability,
GetEntriesProvidingCapabilityCallback callback) {
std::vector<mojom::EntryPtr> entries;
for (const auto& entry : manifest_map_) {
const auto* manifest = entry.second;
if (manifest->exposed_capabilities.find(capability) !=
manifest->exposed_capabilities.end()) {
entries.push_back(mojom::Entry::New(manifest->service_name,
manifest->display_name.raw_string));
}
}
std::move(callback).Run(std::move(entries));
}
} // namespace catalog