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/reader.h" | 5 #include "services/catalog/reader.h" |
6 | 6 |
| 7 #include "base/base_paths.h" |
7 #include "base/bind.h" | 8 #include "base/bind.h" |
8 #include "base/files/file_enumerator.h" | 9 #include "base/files/file_enumerator.h" |
9 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
10 #include "base/json/json_file_value_serializer.h" | 11 #include "base/json/json_file_value_serializer.h" |
11 #include "base/json/json_reader.h" | 12 #include "base/json/json_reader.h" |
12 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
13 #include "base/path_service.h" | 14 #include "base/path_service.h" |
| 15 #include "base/strings/string_util.h" |
| 16 #include "base/strings/utf_string_conversions.h" |
14 #include "base/task_runner_util.h" | 17 #include "base/task_runner_util.h" |
15 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/values.h" |
16 #include "services/catalog/constants.h" | 20 #include "services/catalog/constants.h" |
17 #include "services/catalog/entry.h" | 21 #include "services/catalog/entry.h" |
18 #include "services/catalog/manifest_provider.h" | 22 #include "services/catalog/manifest_provider.h" |
19 #include "services/catalog/public/interfaces/constants.mojom.h" | 23 #include "services/catalog/public/interfaces/constants.mojom.h" |
20 #include "services/service_manager/public/interfaces/constants.mojom.h" | 24 #include "services/service_manager/public/interfaces/constants.mojom.h" |
21 | 25 |
22 namespace catalog { | 26 namespace catalog { |
23 namespace { | 27 namespace { |
24 | 28 |
25 #if defined(OS_WIN) | 29 #if defined(OS_WIN) |
26 const char kServiceExecutableExtension[] = ".service.exe"; | 30 const char kServiceExecutableExtension[] = ".service.exe"; |
27 #else | 31 #else |
28 const char kServiceExecutableExtension[] = ".service"; | 32 const char kServiceExecutableExtension[] = ".service"; |
29 #endif | 33 #endif |
30 | 34 |
| 35 const char kCatalogServicesKey[] = "services"; |
| 36 const char kCatalogServiceEmbeddedKey[] = "embedded"; |
| 37 const char kCatalogServiceExecutableKey[] = "executable"; |
| 38 const char kCatalogServiceManifestKey[] = "manifest"; |
| 39 |
31 base::FilePath GetManifestPath(const base::FilePath& package_dir, | 40 base::FilePath GetManifestPath(const base::FilePath& package_dir, |
32 const std::string& name, | 41 const std::string& name, |
33 const std::string& package_name_override) { | 42 const std::string& package_name_override) { |
34 // TODO(beng): think more about how this should be done for exe targets. | 43 // TODO(beng): think more about how this should be done for exe targets. |
35 std::string package_name = | 44 std::string package_name = |
36 package_name_override.empty() ? name : package_name_override; | 45 package_name_override.empty() ? name : package_name_override; |
37 return package_dir.AppendASCII(kPackagesDirName).AppendASCII( | 46 return package_dir.AppendASCII(kPackagesDirName).AppendASCII( |
38 package_name + "/manifest.json"); | 47 package_name + "/manifest.json"); |
39 } | 48 } |
40 | 49 |
41 base::FilePath GetExecutablePath(const base::FilePath& package_dir, | 50 base::FilePath GetExecutablePath(const base::FilePath& package_dir, |
42 const std::string& name) { | 51 const std::string& name) { |
43 return package_dir.AppendASCII( | 52 return package_dir.AppendASCII( |
44 name + "/" + name + kServiceExecutableExtension); | 53 name + "/" + name + kServiceExecutableExtension); |
45 } | 54 } |
46 | 55 |
47 std::unique_ptr<Entry> ProcessManifest( | 56 std::unique_ptr<Entry> ProcessManifest(const base::Value* manifest_root, |
48 std::unique_ptr<base::Value> manifest_root, | 57 const base::FilePath& package_dir, |
49 const base::FilePath& package_dir) { | 58 const base::FilePath& executable_path) { |
| 59 |
50 // Manifest was malformed or did not exist. | 60 // Manifest was malformed or did not exist. |
51 if (!manifest_root) | 61 if (!manifest_root) |
52 return nullptr; | 62 return nullptr; |
53 | 63 |
54 const base::DictionaryValue* dictionary = nullptr; | 64 const base::DictionaryValue* dictionary = nullptr; |
55 if (!manifest_root->GetAsDictionary(&dictionary)) | 65 if (!manifest_root->GetAsDictionary(&dictionary)) |
56 return nullptr; | 66 return nullptr; |
57 | 67 |
58 std::unique_ptr<Entry> entry = Entry::Deserialize(*dictionary); | 68 std::unique_ptr<Entry> entry = Entry::Deserialize(*dictionary); |
59 if (!entry) | 69 if (!entry) |
60 return nullptr; | 70 return nullptr; |
61 entry->set_path(GetExecutablePath(package_dir, entry->name())); | 71 if (!executable_path.empty()) |
| 72 entry->set_path(executable_path); |
| 73 else |
| 74 entry->set_path(GetExecutablePath(package_dir, entry->name())); |
62 return entry; | 75 return entry; |
63 } | 76 } |
64 | 77 |
| 78 std::unique_ptr<Entry> ProcessUniqueManifest( |
| 79 std::unique_ptr<base::Value> manifest_root, |
| 80 const base::FilePath& package_dir) { |
| 81 return ProcessManifest(manifest_root.get(), package_dir, base::FilePath()); |
| 82 } |
| 83 |
65 std::unique_ptr<Entry> CreateEntryForManifestAt( | 84 std::unique_ptr<Entry> CreateEntryForManifestAt( |
66 const base::FilePath& manifest_path, | 85 const base::FilePath& manifest_path, |
67 const base::FilePath& package_dir) { | 86 const base::FilePath& package_dir) { |
68 JSONFileValueDeserializer deserializer(manifest_path); | 87 JSONFileValueDeserializer deserializer(manifest_path); |
69 int error = 0; | 88 int error = 0; |
70 std::string message; | 89 std::string message; |
71 | 90 |
72 // TODO(beng): probably want to do more detailed error checking. This should | 91 // TODO(beng): probably want to do more detailed error checking. This should |
73 // be done when figuring out if to unblock connection completion. | 92 // be done when figuring out if to unblock connection completion. |
74 return ProcessManifest(deserializer.Deserialize(&error, &message), | 93 return ProcessUniqueManifest(deserializer.Deserialize(&error, &message), |
75 package_dir); | 94 package_dir); |
76 } | 95 } |
77 | 96 |
78 void ScanDir( | 97 void ScanDir( |
79 const base::FilePath& package_dir, | 98 const base::FilePath& package_dir, |
80 const Reader::ReadManifestCallback& read_manifest_callback, | 99 const Reader::ReadManifestCallback& read_manifest_callback, |
81 scoped_refptr<base::SingleThreadTaskRunner> original_thread_task_runner, | 100 scoped_refptr<base::SingleThreadTaskRunner> original_thread_task_runner, |
82 const base::Closure& read_complete_closure) { | 101 const base::Closure& read_complete_closure) { |
83 base::FileEnumerator enumerator(package_dir, false, | 102 base::FileEnumerator enumerator(package_dir, false, |
84 base::FileEnumerator::DIRECTORIES); | 103 base::FileEnumerator::DIRECTORIES); |
85 while (1) { | 104 while (1) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 | 154 |
136 void AddEntryToCache(EntryCache* cache, std::unique_ptr<Entry> entry) { | 155 void AddEntryToCache(EntryCache* cache, std::unique_ptr<Entry> entry) { |
137 std::vector<std::unique_ptr<Entry>> children = entry->TakeChildren(); | 156 std::vector<std::unique_ptr<Entry>> children = entry->TakeChildren(); |
138 for (auto& child : children) | 157 for (auto& child : children) |
139 AddEntryToCache(cache, std::move(child)); | 158 AddEntryToCache(cache, std::move(child)); |
140 (*cache)[entry->name()] = std::move(entry); | 159 (*cache)[entry->name()] = std::move(entry); |
141 } | 160 } |
142 | 161 |
143 void DoNothing(service_manager::mojom::ResolveResultPtr) {} | 162 void DoNothing(service_manager::mojom::ResolveResultPtr) {} |
144 | 163 |
| 164 void LoadCatalogManifestIntoCache(const base::Value* root, |
| 165 const base::FilePath& package_dir, |
| 166 EntryCache* cache) { |
| 167 DCHECK(root); |
| 168 const base::DictionaryValue* catalog = nullptr; |
| 169 if (!root->GetAsDictionary(&catalog)) { |
| 170 LOG(ERROR) << "Catalog manifest is not a dictionary value."; |
| 171 return; |
| 172 } |
| 173 DCHECK(catalog); |
| 174 |
| 175 const base::DictionaryValue* services = nullptr; |
| 176 if (!catalog->GetDictionary(kCatalogServicesKey, &services)) { |
| 177 LOG(ERROR) << "Catalog manifest \"services\" is not a dictionary value."; |
| 178 return; |
| 179 } |
| 180 |
| 181 for (base::DictionaryValue::Iterator it(*services); !it.IsAtEnd(); |
| 182 it.Advance()) { |
| 183 const base::DictionaryValue* service_entry = nullptr; |
| 184 if (!it.value().GetAsDictionary(&service_entry)) { |
| 185 LOG(ERROR) << "Catalog service entry for \"" << it.key() |
| 186 << "\" is not a dictionary value."; |
| 187 continue; |
| 188 } |
| 189 |
| 190 bool is_embedded = false; |
| 191 service_entry->GetBoolean(kCatalogServiceEmbeddedKey, &is_embedded); |
| 192 |
| 193 base::FilePath executable_path; |
| 194 std::string executable_path_string; |
| 195 if (service_entry->GetString(kCatalogServiceExecutableKey, |
| 196 &executable_path_string)) { |
| 197 base::FilePath exe_dir; |
| 198 CHECK(base::PathService::Get(base::DIR_EXE, &exe_dir)); |
| 199 #if defined(OS_WIN) |
| 200 executable_path_string += ".exe"; |
| 201 base::ReplaceFirstSubstringAfterOffset( |
| 202 &executable_path_string, 0, "@EXE_DIR", |
| 203 base::UTF16ToUTF8(exe_dir.value())); |
| 204 executable_path = |
| 205 base::FilePath(base::UTF8ToUTF16(executable_path_string)); |
| 206 #else |
| 207 base::ReplaceFirstSubstringAfterOffset( |
| 208 &executable_path_string, 0, "@EXE_DIR", exe_dir.value()); |
| 209 executable_path = base::FilePath(executable_path_string); |
| 210 #endif |
| 211 } |
| 212 |
| 213 const base::DictionaryValue* manifest = nullptr; |
| 214 if (!service_entry->GetDictionary(kCatalogServiceManifestKey, &manifest)) { |
| 215 LOG(ERROR) << "Catalog entry for \"" << it.key() << "\" has an invalid " |
| 216 << "\"manifest\" value."; |
| 217 continue; |
| 218 } |
| 219 |
| 220 DCHECK(!(is_embedded && !executable_path.empty())); |
| 221 |
| 222 auto entry = ProcessManifest( |
| 223 manifest, is_embedded ? base::FilePath() : package_dir, |
| 224 executable_path); |
| 225 if (entry) |
| 226 AddEntryToCache(cache, std::move(entry)); |
| 227 else |
| 228 LOG(ERROR) << "Failed to read manifest entry for \"" << it.key() << "\"."; |
| 229 } |
| 230 } |
| 231 |
145 } // namespace | 232 } // namespace |
146 | 233 |
| 234 Reader::Reader(std::unique_ptr<base::Value> static_manifest, |
| 235 EntryCache* cache) |
| 236 : using_static_catalog_(true), |
| 237 manifest_provider_(nullptr), |
| 238 weak_factory_(this) { |
| 239 PathService::Get(base::DIR_MODULE, &system_package_dir_); |
| 240 LoadCatalogManifestIntoCache( |
| 241 static_manifest.get(), system_package_dir_.AppendASCII(kPackagesDirName), |
| 242 cache); |
| 243 } |
| 244 |
147 // A sequenced task runner is used to guarantee requests are serviced in the | 245 // A sequenced task runner is used to guarantee requests are serviced in the |
148 // order requested. To do otherwise means we may run callbacks in an | 246 // order requested. To do otherwise means we may run callbacks in an |
149 // unpredictable order, leading to flake. | 247 // unpredictable order, leading to flake. |
150 Reader::Reader(base::SequencedWorkerPool* worker_pool, | 248 Reader::Reader(base::SequencedWorkerPool* worker_pool, |
151 ManifestProvider* manifest_provider) | 249 ManifestProvider* manifest_provider) |
152 : Reader(manifest_provider) { | 250 : Reader(manifest_provider) { |
153 file_task_runner_ = worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | 251 file_task_runner_ = worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( |
154 base::SequencedWorkerPool::GetSequenceToken(), | 252 base::SequencedWorkerPool::GetSequenceToken(), |
155 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 253 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
156 } | 254 } |
(...skipping 21 matching lines...) Expand all Loading... |
178 void Reader::CreateEntryForName( | 276 void Reader::CreateEntryForName( |
179 const std::string& mojo_name, | 277 const std::string& mojo_name, |
180 EntryCache* cache, | 278 EntryCache* cache, |
181 const CreateEntryForNameCallback& entry_created_callback) { | 279 const CreateEntryForNameCallback& entry_created_callback) { |
182 if (manifest_provider_) { | 280 if (manifest_provider_) { |
183 std::unique_ptr<base::Value> manifest_root = | 281 std::unique_ptr<base::Value> manifest_root = |
184 manifest_provider_->GetManifest(mojo_name); | 282 manifest_provider_->GetManifest(mojo_name); |
185 if (manifest_root) { | 283 if (manifest_root) { |
186 base::PostTaskAndReplyWithResult( | 284 base::PostTaskAndReplyWithResult( |
187 file_task_runner_.get(), FROM_HERE, | 285 file_task_runner_.get(), FROM_HERE, |
188 base::Bind(&ProcessManifest, base::Passed(&manifest_root), | 286 base::Bind(&ProcessUniqueManifest, base::Passed(&manifest_root), |
189 system_package_dir_), | 287 system_package_dir_), |
190 base::Bind(&Reader::OnReadManifest, weak_factory_.GetWeakPtr(), cache, | 288 base::Bind(&Reader::OnReadManifest, weak_factory_.GetWeakPtr(), cache, |
191 entry_created_callback)); | 289 entry_created_callback)); |
192 return; | 290 return; |
193 } | 291 } |
| 292 } else if (using_static_catalog_) { |
| 293 // A Reader using a static catalog manifest does not support dynamic |
| 294 // discovery or introduction of new catalog entries. |
| 295 entry_created_callback.Run(service_manager::mojom::ResolveResultPtr()); |
| 296 return; |
194 } | 297 } |
195 | 298 |
196 base::FilePath manifest_path_override; | 299 base::FilePath manifest_path_override; |
197 { | 300 { |
198 auto override_iter = manifest_path_overrides_.find(mojo_name); | 301 auto override_iter = manifest_path_overrides_.find(mojo_name); |
199 if (override_iter != manifest_path_overrides_.end()) | 302 if (override_iter != manifest_path_overrides_.end()) |
200 manifest_path_override = override_iter->second; | 303 manifest_path_override = override_iter->second; |
201 } | 304 } |
202 | 305 |
203 std::string package_name_override; | 306 std::string package_name_override; |
(...skipping 14 matching lines...) Expand all Loading... |
218 const std::string& package_name) { | 321 const std::string& package_name) { |
219 package_name_overrides_.insert(std::make_pair(service_name, package_name)); | 322 package_name_overrides_.insert(std::make_pair(service_name, package_name)); |
220 } | 323 } |
221 | 324 |
222 void Reader::OverrideManifestPath(const std::string& service_name, | 325 void Reader::OverrideManifestPath(const std::string& service_name, |
223 const base::FilePath& path) { | 326 const base::FilePath& path) { |
224 manifest_path_overrides_.insert(std::make_pair(service_name, path)); | 327 manifest_path_overrides_.insert(std::make_pair(service_name, path)); |
225 } | 328 } |
226 | 329 |
227 Reader::Reader(ManifestProvider* manifest_provider) | 330 Reader::Reader(ManifestProvider* manifest_provider) |
228 : manifest_provider_(manifest_provider), weak_factory_(this) { | 331 : using_static_catalog_(false), |
| 332 manifest_provider_(manifest_provider), |
| 333 weak_factory_(this) { |
229 PathService::Get(base::DIR_MODULE, &system_package_dir_); | 334 PathService::Get(base::DIR_MODULE, &system_package_dir_); |
230 } | 335 } |
231 | 336 |
232 void Reader::OnReadManifest( | 337 void Reader::OnReadManifest( |
233 EntryCache* cache, | 338 EntryCache* cache, |
234 const CreateEntryForNameCallback& entry_created_callback, | 339 const CreateEntryForNameCallback& entry_created_callback, |
235 std::unique_ptr<Entry> entry) { | 340 std::unique_ptr<Entry> entry) { |
236 if (!entry) | 341 if (!entry) |
237 return; | 342 return; |
238 service_manager::mojom::ResolveResultPtr result = | 343 service_manager::mojom::ResolveResultPtr result = |
239 service_manager::mojom::ResolveResult::From(*entry); | 344 service_manager::mojom::ResolveResult::From(*entry); |
240 AddEntryToCache(cache, std::move(entry)); | 345 AddEntryToCache(cache, std::move(entry)); |
241 entry_created_callback.Run(std::move(result)); | 346 entry_created_callback.Run(std::move(result)); |
242 } | 347 } |
243 | 348 |
244 } // namespace catalog | 349 } // namespace catalog |
OLD | NEW |