blob: 5d94c7ce596dc339b62925a9b3adc443f19f6c81 [file] [log] [blame]
// Copyright 2017 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/entry_cache.h"
#include <map>
#include <set>
#include <string>
#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "build/build_config.h"
#include "services/catalog/entry.h"
#include "services/service_manager/public/cpp/interface_provider_spec.h"
#include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
namespace catalog {
namespace {
#if defined(OS_WIN)
const char kServiceExecutableExtension[] = ".service.exe";
#else
const char kServiceExecutableExtension[] = ".service";
#endif
// Temporary helper to create a cache Entry from a Manifest object. This can
// disappear once the Service Manager just uses Manifest objects directly.
std::unique_ptr<Entry> MakeEntryFromManifest(
const service_manager::Manifest& manifest) {
auto entry = std::make_unique<Entry>();
entry->set_name(manifest.service_name);
entry->set_display_name(manifest.display_name.raw_string);
base::FilePath service_exe_root;
CHECK(base::PathService::Get(base::DIR_ASSETS, &service_exe_root));
entry->set_path(service_exe_root.AppendASCII(entry->name() +
kServiceExecutableExtension));
entry->set_sandbox_type(manifest.options.sandbox_type);
ServiceOptions options;
switch (manifest.options.instance_sharing_policy) {
case service_manager::Manifest::InstanceSharingPolicy::kNoSharing:
options.instance_sharing = ServiceOptions::InstanceSharingType::NONE;
break;
case service_manager::Manifest::InstanceSharingPolicy::kSingleton:
options.instance_sharing = ServiceOptions::InstanceSharingType::SINGLETON;
break;
case service_manager::Manifest::InstanceSharingPolicy::kSharedAcrossGroups:
options.instance_sharing =
ServiceOptions::InstanceSharingType::SHARED_ACROSS_INSTANCE_GROUPS;
break;
}
options.can_connect_to_instances_in_any_group =
manifest.options.can_connect_to_instances_in_any_group;
options.can_connect_to_other_services_with_any_instance_name =
manifest.options.can_connect_to_instances_with_any_id;
options.can_create_other_service_instances =
manifest.options.can_register_other_service_instances;
options.interfaces_bindable_on_any_service =
manifest.interfaces_bindable_on_any_service;
entry->AddOptions(options);
service_manager::InterfaceProviderSpec main_spec;
for (const auto& entry : manifest.exposed_capabilities)
main_spec.provides.emplace(entry.capability_name, entry.interface_names);
for (const auto& entry : manifest.required_capabilities) {
main_spec.requires[entry.service_name].insert(entry.capability_name);
}
entry->AddInterfaceProviderSpec(
service_manager::mojom::kServiceManager_ConnectorSpec,
std::move(main_spec));
std::map<std::string, service_manager::InterfaceProviderSpec> other_specs;
for (const auto& entry : manifest.exposed_interface_filter_capabilities) {
other_specs[entry.filter_name].provides.emplace(entry.capability_name,
entry.interface_names);
}
for (const auto& entry : manifest.required_interface_filter_capabilities) {
other_specs[entry.filter_name].requires[entry.service_name].insert(
entry.capability_name);
}
for (auto& spec : other_specs)
entry->AddInterfaceProviderSpec(spec.first, std::move(spec.second));
for (const auto& file : manifest.preloaded_files)
entry->AddRequiredFilePath(file.key, file.path);
for (const auto& packaged_service_manifest : manifest.packaged_services) {
auto child = MakeEntryFromManifest(packaged_service_manifest);
child->set_parent(entry.get());
entry->children().emplace_back(std::move(child));
}
return entry;
}
} // namespace
EntryCache::EntryCache() {}
EntryCache::~EntryCache() {}
bool EntryCache::AddRootEntry(std::unique_ptr<Entry> entry) {
DCHECK(entry);
const std::string& name = entry->name();
if (!AddEntry(entry.get()))
return false;
root_entries_.insert(std::make_pair(name, std::move(entry)));
return true;
}
bool EntryCache::AddRootEntryFromManifest(
const service_manager::Manifest& manifest) {
return AddRootEntry(MakeEntryFromManifest(manifest));
}
const Entry* EntryCache::GetEntry(const std::string& name) {
auto iter = entries_.find(name);
if (iter == entries_.end())
return nullptr;
return iter->second;
}
bool EntryCache::AddEntry(const Entry* entry) {
auto root_iter = root_entries_.find(entry->name());
if (root_iter != root_entries_.end()) {
RemoveEntry(root_iter->second.get());
root_entries_.erase(root_iter);
} else {
auto entry_iter = entries_.find(entry->name());
if (entry_iter != entries_.end()) {
// There's already a non-root entry for this name, so we change nothing.
return false;
}
}
entries_.insert({ entry->name(), entry });
for (const auto& child : entry->children())
AddEntry(child.get());
return true;
}
void EntryCache::RemoveEntry(const Entry* entry) {
auto iter = entries_.find(entry->name());
if (iter->second == entry)
entries_.erase(iter);
for (const auto& child : entry->children())
RemoveEntry(child.get());
}
} // namespace catalog