OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "services/catalog/catalog.h" | 5 #include "services/catalog/catalog.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include <memory> |
| 8 #include <string> |
| 9 |
| 10 #include "base/base_paths.h" |
8 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
9 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/json/json_reader.h" |
| 14 #include "base/lazy_instance.h" |
10 #include "base/macros.h" | 15 #include "base/macros.h" |
11 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
12 #include "base/path_service.h" | 17 #include "base/path_service.h" |
13 #include "base/strings/string_split.h" | |
14 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 19 #include "base/strings/utf_string_conversions.h" |
15 #include "components/filesystem/directory_impl.h" | 20 #include "components/filesystem/directory_impl.h" |
16 #include "components/filesystem/lock_table.h" | 21 #include "components/filesystem/lock_table.h" |
17 #include "components/filesystem/public/interfaces/types.mojom.h" | 22 #include "components/filesystem/public/interfaces/types.mojom.h" |
18 #include "mojo/public/cpp/bindings/strong_binding.h" | 23 #include "mojo/public/cpp/bindings/strong_binding.h" |
19 #include "services/catalog/constants.h" | 24 #include "services/catalog/constants.h" |
20 #include "services/catalog/entry_cache.h" | 25 #include "services/catalog/entry_cache.h" |
21 #include "services/catalog/instance.h" | 26 #include "services/catalog/instance.h" |
22 #include "services/catalog/reader.h" | |
23 #include "services/service_manager/public/cpp/connection.h" | 27 #include "services/service_manager/public/cpp/connection.h" |
24 #include "services/service_manager/public/cpp/interface_registry.h" | 28 #include "services/service_manager/public/cpp/interface_registry.h" |
25 #include "services/service_manager/public/cpp/service_context.h" | 29 #include "services/service_manager/public/cpp/service_context.h" |
26 | 30 |
27 namespace catalog { | 31 namespace catalog { |
| 32 |
28 namespace { | 33 namespace { |
29 | 34 |
30 bool IsPathNameValid(const std::string& name) { | 35 const char kCatalogServicesKey[] = "services"; |
31 if (name.empty() || name == "." || name == "..") | 36 const char kCatalogServiceEmbeddedKey[] = "embedded"; |
32 return false; | 37 const char kCatalogServiceExecutableKey[] = "executable"; |
| 38 const char kCatalogServiceManifestKey[] = "manifest"; |
33 | 39 |
34 for (auto c : name) { | 40 base::LazyInstance<std::unique_ptr<base::Value>> g_default_static_manifest = |
35 if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) && | 41 LAZY_INSTANCE_INITIALIZER; |
36 c != '_' && c != '.') | 42 |
37 return false; | 43 void LoadCatalogManifestIntoCache(const base::Value* root, EntryCache* cache) { |
| 44 DCHECK(root); |
| 45 const base::DictionaryValue* catalog = nullptr; |
| 46 if (!root->GetAsDictionary(&catalog)) { |
| 47 LOG(ERROR) << "Catalog manifest is not a dictionary value."; |
| 48 return; |
38 } | 49 } |
39 return true; | 50 DCHECK(catalog); |
40 } | |
41 | 51 |
42 base::FilePath GetPathForApplicationName(const std::string& application_name) { | 52 const base::DictionaryValue* services = nullptr; |
43 static const char kServicePrefix[] = ""; | 53 if (!catalog->GetDictionary(kCatalogServicesKey, &services)) { |
44 std::string path = application_name; | 54 LOG(ERROR) << "Catalog manifest \"services\" is not a dictionary value."; |
45 const bool is_service = base::StartsWith( | 55 return; |
46 path, kServicePrefix, base::CompareCase::INSENSITIVE_ASCII); | 56 } |
47 if (!is_service) | |
48 return base::FilePath(); | |
49 if (path.find('.') != std::string::npos) | |
50 return base::FilePath(); | |
51 path.erase(path.begin(), path.begin() + strlen(kServicePrefix)); | |
52 base::TrimString(path, "/", &path); | |
53 size_t end_of_name = path.find('/'); | |
54 if (end_of_name != std::string::npos) | |
55 path.erase(path.begin() + end_of_name, path.end()); | |
56 | 57 |
57 if (!IsPathNameValid(path)) | 58 for (base::DictionaryValue::Iterator it(*services); !it.IsAtEnd(); |
58 return base::FilePath(); | 59 it.Advance()) { |
| 60 const base::DictionaryValue* service_entry = nullptr; |
| 61 if (!it.value().GetAsDictionary(&service_entry)) { |
| 62 LOG(ERROR) << "Catalog service entry for \"" << it.key() |
| 63 << "\" is not a dictionary value."; |
| 64 continue; |
| 65 } |
59 | 66 |
60 base::FilePath base_path; | 67 bool is_embedded = false; |
61 PathService::Get(base::DIR_EXE, &base_path); | 68 service_entry->GetBoolean(kCatalogServiceEmbeddedKey, &is_embedded); |
62 // TODO(beng): this won't handle user-specific components. | 69 |
63 return base_path.AppendASCII(kPackagesDirName).AppendASCII(path). | 70 base::FilePath executable_path; |
64 AppendASCII("resources"); | 71 std::string executable_path_string; |
| 72 if (service_entry->GetString(kCatalogServiceExecutableKey, |
| 73 &executable_path_string)) { |
| 74 base::FilePath exe_dir; |
| 75 CHECK(base::PathService::Get(base::DIR_EXE, &exe_dir)); |
| 76 #if defined(OS_WIN) |
| 77 executable_path_string += ".exe"; |
| 78 base::ReplaceFirstSubstringAfterOffset( |
| 79 &executable_path_string, 0, "@EXE_DIR", |
| 80 base::UTF16ToUTF8(exe_dir.value())); |
| 81 executable_path = |
| 82 base::FilePath(base::UTF8ToUTF16(executable_path_string)); |
| 83 #else |
| 84 base::ReplaceFirstSubstringAfterOffset( |
| 85 &executable_path_string, 0, "@EXE_DIR", exe_dir.value()); |
| 86 executable_path = base::FilePath(executable_path_string); |
| 87 #endif |
| 88 } |
| 89 |
| 90 const base::DictionaryValue* manifest = nullptr; |
| 91 if (!service_entry->GetDictionary(kCatalogServiceManifestKey, &manifest)) { |
| 92 LOG(ERROR) << "Catalog entry for \"" << it.key() << "\" has an invalid " |
| 93 << "\"manifest\" value."; |
| 94 continue; |
| 95 } |
| 96 |
| 97 DCHECK(!(is_embedded && !executable_path.empty())); |
| 98 |
| 99 auto entry = Entry::Deserialize(*manifest); |
| 100 if (entry) { |
| 101 if (!executable_path.empty()) |
| 102 entry->set_path(executable_path); |
| 103 bool added = cache->AddRootEntry(std::move(entry)); |
| 104 DCHECK(added); |
| 105 } else { |
| 106 LOG(ERROR) << "Failed to read manifest entry for \"" << it.key() << "\"."; |
| 107 } |
| 108 } |
65 } | 109 } |
66 | 110 |
67 } // namespace | 111 } // namespace |
68 | 112 |
69 class Catalog::ServiceImpl : public service_manager::Service { | 113 class Catalog::ServiceImpl : public service_manager::Service { |
70 public: | 114 public: |
71 explicit ServiceImpl(Catalog* catalog) : catalog_(catalog) {} | 115 explicit ServiceImpl(Catalog* catalog) : catalog_(catalog) {} |
72 ~ServiceImpl() override {} | 116 ~ServiceImpl() override {} |
73 | 117 |
74 // service_manager::Service: | 118 // service_manager::Service: |
75 bool OnConnect(const service_manager::ServiceInfo& remote_info, | 119 bool OnConnect(const service_manager::ServiceInfo& remote_info, |
76 service_manager::InterfaceRegistry* registry) override { | 120 service_manager::InterfaceRegistry* registry) override { |
77 registry->AddInterface<mojom::Catalog>(catalog_); | 121 registry->AddInterface<mojom::Catalog>(catalog_); |
78 registry->AddInterface<mojom::CatalogControl>(catalog_); | |
79 registry->AddInterface<filesystem::mojom::Directory>(catalog_); | 122 registry->AddInterface<filesystem::mojom::Directory>(catalog_); |
80 registry->AddInterface<service_manager::mojom::Resolver>(catalog_); | 123 registry->AddInterface<service_manager::mojom::Resolver>(catalog_); |
81 return true; | 124 return true; |
82 } | 125 } |
83 | 126 |
84 private: | 127 private: |
85 Catalog* const catalog_; | 128 Catalog* const catalog_; |
86 | 129 |
87 DISALLOW_COPY_AND_ASSIGN(ServiceImpl); | 130 DISALLOW_COPY_AND_ASSIGN(ServiceImpl); |
88 }; | 131 }; |
89 | 132 |
90 Catalog::Catalog(std::unique_ptr<base::Value> static_manifest) : Catalog() { | 133 Catalog::Catalog(std::unique_ptr<base::Value> static_manifest, |
91 system_reader_.reset(new Reader(std::move(static_manifest), | 134 ManifestProvider* service_manifest_provider) |
92 system_cache_.get())); | 135 : service_context_(new service_manager::ServiceContext( |
93 loaded_ = true; | 136 base::MakeUnique<ServiceImpl>(this), |
94 } | 137 service_manager::mojom::ServiceRequest(&service_))), |
95 | 138 service_manifest_provider_(service_manifest_provider), |
96 Catalog::Catalog(base::SequencedWorkerPool* worker_pool, | 139 weak_factory_(this) { |
97 ManifestProvider* manifest_provider) : Catalog() { | 140 if (static_manifest) { |
98 system_reader_.reset(new Reader(worker_pool, manifest_provider)); | 141 LoadCatalogManifestIntoCache(static_manifest.get(), &system_cache_); |
99 ScanSystemPackageDir(); | 142 } else if (g_default_static_manifest.Get()) { |
100 } | 143 LoadCatalogManifestIntoCache( |
101 | 144 g_default_static_manifest.Get().get(), &system_cache_); |
102 Catalog::Catalog(base::SingleThreadTaskRunner* task_runner, | 145 } |
103 ManifestProvider* manifest_provider) : Catalog() { | |
104 system_reader_.reset(new Reader(task_runner, manifest_provider)); | |
105 ScanSystemPackageDir(); | |
106 } | 146 } |
107 | 147 |
108 Catalog::~Catalog() {} | 148 Catalog::~Catalog() {} |
109 | 149 |
110 void Catalog::OverridePackageName(const std::string& service_name, | |
111 const std::string& package_name) { | |
112 system_reader_->OverridePackageName(service_name, package_name); | |
113 } | |
114 | |
115 service_manager::mojom::ServicePtr Catalog::TakeService() { | 150 service_manager::mojom::ServicePtr Catalog::TakeService() { |
116 return std::move(service_); | 151 return std::move(service_); |
117 } | 152 } |
118 | 153 |
119 Catalog::Catalog() : system_cache_(new EntryCache), weak_factory_(this) { | 154 // static |
120 service_context_.reset(new service_manager::ServiceContext( | 155 void Catalog::SetDefaultCatalogManifest( |
121 base::MakeUnique<ServiceImpl>(this), | 156 std::unique_ptr<base::Value> static_manifest) { |
122 service_manager::mojom::ServiceRequest(&service_))); | 157 g_default_static_manifest.Get() = std::move(static_manifest); |
123 } | 158 } |
124 | 159 |
125 void Catalog::ScanSystemPackageDir() { | 160 // static |
126 base::FilePath system_package_dir; | 161 void Catalog::LoadDefaultCatalogManifest(const base::FilePath& path) { |
127 PathService::Get(base::DIR_MODULE, &system_package_dir); | 162 std::string catalog_contents; |
128 system_package_dir = system_package_dir.AppendASCII(kPackagesDirName); | 163 base::FilePath exe_path; |
129 system_reader_->Read(system_package_dir, system_cache_.get(), | 164 base::PathService::Get(base::DIR_EXE, &exe_path); |
130 base::Bind(&Catalog::SystemPackageDirScanned, | 165 base::FilePath catalog_path = exe_path.Append(path); |
131 weak_factory_.GetWeakPtr())); | 166 bool result = base::ReadFileToString(catalog_path, &catalog_contents); |
| 167 DCHECK(result); |
| 168 std::unique_ptr<base::Value> manifest_value = |
| 169 base::JSONReader::Read(catalog_contents); |
| 170 DCHECK(manifest_value); |
| 171 catalog::Catalog::SetDefaultCatalogManifest(std::move(manifest_value)); |
132 } | 172 } |
133 | 173 |
134 void Catalog::Create(const service_manager::Identity& remote_identity, | 174 void Catalog::Create(const service_manager::Identity& remote_identity, |
135 service_manager::mojom::ResolverRequest request) { | 175 service_manager::mojom::ResolverRequest request) { |
136 Instance* instance = GetInstanceForUserId(remote_identity.user_id()); | 176 Instance* instance = GetInstanceForUserId(remote_identity.user_id()); |
137 instance->BindResolver(std::move(request)); | 177 instance->BindResolver(std::move(request)); |
138 } | 178 } |
139 | 179 |
140 void Catalog::Create(const service_manager::Identity& remote_identity, | 180 void Catalog::Create(const service_manager::Identity& remote_identity, |
141 mojom::CatalogRequest request) { | 181 mojom::CatalogRequest request) { |
142 Instance* instance = GetInstanceForUserId(remote_identity.user_id()); | 182 Instance* instance = GetInstanceForUserId(remote_identity.user_id()); |
143 instance->BindCatalog(std::move(request)); | 183 instance->BindCatalog(std::move(request)); |
144 } | 184 } |
145 | 185 |
146 void Catalog::Create(const service_manager::Identity& remote_identity, | 186 void Catalog::Create(const service_manager::Identity& remote_identity, |
147 filesystem::mojom::DirectoryRequest request) { | 187 filesystem::mojom::DirectoryRequest request) { |
148 if (!lock_table_) | 188 if (!lock_table_) |
149 lock_table_ = new filesystem::LockTable; | 189 lock_table_ = new filesystem::LockTable; |
150 base::FilePath resources_path = | 190 |
151 GetPathForApplicationName(remote_identity.name()); | 191 base::FilePath resources_path; |
| 192 base::PathService::Get(base::DIR_MODULE, &resources_path); |
152 mojo::MakeStrongBinding( | 193 mojo::MakeStrongBinding( |
153 base::MakeUnique<filesystem::DirectoryImpl>( | 194 base::MakeUnique<filesystem::DirectoryImpl>( |
154 resources_path, scoped_refptr<filesystem::SharedTempDir>(), | 195 resources_path, scoped_refptr<filesystem::SharedTempDir>(), |
155 lock_table_), | 196 lock_table_), |
156 std::move(request)); | 197 std::move(request)); |
157 } | 198 } |
158 | 199 |
159 void Catalog::Create(const service_manager::Identity& remote_identity, | |
160 mojom::CatalogControlRequest request) { | |
161 control_bindings_.AddBinding(this, std::move(request)); | |
162 } | |
163 | |
164 void Catalog::OverrideManifestPath( | |
165 const std::string& service_name, | |
166 const base::FilePath& path, | |
167 const OverrideManifestPathCallback& callback) { | |
168 system_reader_->OverrideManifestPath(service_name, path); | |
169 callback.Run(); | |
170 } | |
171 | |
172 Instance* Catalog::GetInstanceForUserId(const std::string& user_id) { | 200 Instance* Catalog::GetInstanceForUserId(const std::string& user_id) { |
173 auto it = instances_.find(user_id); | 201 auto it = instances_.find(user_id); |
174 if (it != instances_.end()) | 202 if (it != instances_.end()) |
175 return it->second.get(); | 203 return it->second.get(); |
176 | 204 |
177 Instance* instance = new Instance(system_reader_.get()); | 205 auto result = instances_.insert(std::make_pair( |
178 instances_[user_id] = base::WrapUnique(instance); | 206 user_id, |
179 if (loaded_) | 207 base::MakeUnique<Instance>(&system_cache_, service_manifest_provider_))); |
180 instance->CacheReady(system_cache_.get()); | 208 return result.first->second.get(); |
181 | |
182 return instance; | |
183 } | |
184 | |
185 void Catalog::SystemPackageDirScanned() { | |
186 loaded_ = true; | |
187 for (auto& instance : instances_) | |
188 instance.second->CacheReady(system_cache_.get()); | |
189 } | 209 } |
190 | 210 |
191 } // namespace catalog | 211 } // namespace catalog |
OLD | NEW |