OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" | 5 #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" |
6 | 6 |
7 #include "base/atomicops.h" | 7 #include "base/atomicops.h" |
8 #include "base/base_paths.h" | 8 #include "base/base_paths.h" |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 } | 83 } |
84 | 84 |
85 // Tell the rest of the world where to find the platform-specific PNaCl files. | 85 // Tell the rest of the world where to find the platform-specific PNaCl files. |
86 void OverrideDirPnaclComponent(const base::FilePath& base_path) { | 86 void OverrideDirPnaclComponent(const base::FilePath& base_path) { |
87 PathService::Override(chrome::DIR_PNACL_COMPONENT, | 87 PathService::Override(chrome::DIR_PNACL_COMPONENT, |
88 GetPlatformDir(base_path)); | 88 GetPlatformDir(base_path)); |
89 } | 89 } |
90 | 90 |
91 bool GetLatestPnaclDirectory(PnaclComponentInstaller* pci, | 91 bool GetLatestPnaclDirectory(PnaclComponentInstaller* pci, |
92 base::FilePath* latest_dir, | 92 base::FilePath* latest_dir, |
93 base::Version* latest_version, | 93 Version* latest_version, |
94 std::vector<base::FilePath>* older_dirs) { | 94 std::vector<base::FilePath>* older_dirs) { |
95 // Enumerate all versions starting from the base directory. | 95 // Enumerate all versions starting from the base directory. |
96 base::FilePath base_dir = pci->GetPnaclBaseDirectory(); | 96 base::FilePath base_dir = pci->GetPnaclBaseDirectory(); |
97 bool found = false; | 97 bool found = false; |
98 base::FileEnumerator | 98 base::FileEnumerator |
99 file_enumerator(base_dir, false, base::FileEnumerator::DIRECTORIES); | 99 file_enumerator(base_dir, false, base::FileEnumerator::DIRECTORIES); |
100 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); | 100 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); |
101 path = file_enumerator.Next()) { | 101 path = file_enumerator.Next()) { |
102 base::Version version(path.BaseName().MaybeAsASCII()); | 102 Version version(path.BaseName().MaybeAsASCII()); |
103 if (!version.IsValid()) | 103 if (!version.IsValid()) |
104 continue; | 104 continue; |
105 if (found) { | 105 if (found) { |
106 if (version.CompareTo(*latest_version) > 0) { | 106 if (version.CompareTo(*latest_version) > 0) { |
107 older_dirs->push_back(*latest_dir); | 107 older_dirs->push_back(*latest_dir); |
108 *latest_dir = path; | 108 *latest_dir = path; |
109 *latest_version = version; | 109 *latest_version = version; |
110 } else { | 110 } else { |
111 older_dirs->push_back(path); | 111 older_dirs->push_back(path); |
112 } | 112 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 FILE_PATH_LITERAL("manifest.json")); | 148 FILE_PATH_LITERAL("manifest.json")); |
149 if (!base::PathExists(manifest_path)) | 149 if (!base::PathExists(manifest_path)) |
150 return NULL; | 150 return NULL; |
151 return ReadJSONManifest(manifest_path); | 151 return ReadJSONManifest(manifest_path); |
152 } | 152 } |
153 | 153 |
154 // Check that the component's manifest is for PNaCl, and check the | 154 // Check that the component's manifest is for PNaCl, and check the |
155 // PNaCl manifest indicates this is the correct arch-specific package. | 155 // PNaCl manifest indicates this is the correct arch-specific package. |
156 bool CheckPnaclComponentManifest(const base::DictionaryValue& manifest, | 156 bool CheckPnaclComponentManifest(const base::DictionaryValue& manifest, |
157 const base::DictionaryValue& pnacl_manifest, | 157 const base::DictionaryValue& pnacl_manifest, |
158 base::Version* version_out) { | 158 Version* version_out) { |
159 // Make sure we have the right |manifest| file. | 159 // Make sure we have the right |manifest| file. |
160 std::string name; | 160 std::string name; |
161 if (!manifest.GetStringASCII("name", &name)) { | 161 if (!manifest.GetStringASCII("name", &name)) { |
162 LOG(WARNING) << "'name' field is missing from manifest!"; | 162 LOG(WARNING) << "'name' field is missing from manifest!"; |
163 return false; | 163 return false; |
164 } | 164 } |
165 // For the webstore, we've given different names to each of the | 165 // For the webstore, we've given different names to each of the |
166 // architecture specific packages (and test/QA vs not test/QA) | 166 // architecture specific packages (and test/QA vs not test/QA) |
167 // so only part of it is the same. | 167 // so only part of it is the same. |
168 if (name.find(kPnaclManifestName) == std::string::npos) { | 168 if (name.find(kPnaclManifestName) == std::string::npos) { |
169 LOG(WARNING) << "'name' field in manifest is invalid (" | 169 LOG(WARNING) << "'name' field in manifest is invalid (" |
170 << name << ") -- missing (" | 170 << name << ") -- missing (" |
171 << kPnaclManifestName << ")"; | 171 << kPnaclManifestName << ")"; |
172 return false; | 172 return false; |
173 } | 173 } |
174 | 174 |
175 std::string proposed_version; | 175 std::string proposed_version; |
176 if (!manifest.GetStringASCII("version", &proposed_version)) { | 176 if (!manifest.GetStringASCII("version", &proposed_version)) { |
177 LOG(WARNING) << "'version' field is missing from manifest!"; | 177 LOG(WARNING) << "'version' field is missing from manifest!"; |
178 return false; | 178 return false; |
179 } | 179 } |
180 base::Version version(proposed_version.c_str()); | 180 Version version(proposed_version.c_str()); |
181 if (!version.IsValid()) { | 181 if (!version.IsValid()) { |
182 LOG(WARNING) << "'version' field in manifest is invalid " | 182 LOG(WARNING) << "'version' field in manifest is invalid " |
183 << version.GetString(); | 183 << version.GetString(); |
184 return false; | 184 return false; |
185 } | 185 } |
186 | 186 |
187 // Now check the |pnacl_manifest|. | 187 // Now check the |pnacl_manifest|. |
188 std::string arch; | 188 std::string arch; |
189 if (!pnacl_manifest.GetStringASCII("pnacl-arch", &arch)) { | 189 if (!pnacl_manifest.GetStringASCII("pnacl-arch", &arch)) { |
190 LOG(WARNING) << "'pnacl-arch' field is missing from pnacl-manifest!"; | 190 LOG(WARNING) << "'pnacl-arch' field is missing from pnacl-manifest!"; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 | 252 |
253 bool PnaclComponentInstaller::Install(const base::DictionaryValue& manifest, | 253 bool PnaclComponentInstaller::Install(const base::DictionaryValue& manifest, |
254 const base::FilePath& unpack_path) { | 254 const base::FilePath& unpack_path) { |
255 scoped_ptr<base::DictionaryValue> pnacl_manifest( | 255 scoped_ptr<base::DictionaryValue> pnacl_manifest( |
256 ReadPnaclManifest(unpack_path)); | 256 ReadPnaclManifest(unpack_path)); |
257 if (pnacl_manifest == NULL) { | 257 if (pnacl_manifest == NULL) { |
258 LOG(WARNING) << "Failed to read pnacl manifest."; | 258 LOG(WARNING) << "Failed to read pnacl manifest."; |
259 return false; | 259 return false; |
260 } | 260 } |
261 | 261 |
262 base::Version version; | 262 Version version; |
263 if (!CheckPnaclComponentManifest(manifest, *pnacl_manifest, &version)) { | 263 if (!CheckPnaclComponentManifest(manifest, *pnacl_manifest, &version)) { |
264 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing."; | 264 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing."; |
265 return false; | 265 return false; |
266 } | 266 } |
267 | 267 |
268 // Don't install if the current version is actually newer. | 268 // Don't install if the current version is actually newer. |
269 if (current_version().CompareTo(version) > 0) { | 269 if (current_version().CompareTo(version) > 0) { |
270 return false; | 270 return false; |
271 } | 271 } |
272 | 272 |
(...skipping 17 matching lines...) Expand all Loading... |
290 OverrideDirPnaclComponent(path); | 290 OverrideDirPnaclComponent(path); |
291 return true; | 291 return true; |
292 } | 292 } |
293 | 293 |
294 // Given |file|, which can be a path like "_platform_specific/arm/pnacl_foo", | 294 // Given |file|, which can be a path like "_platform_specific/arm/pnacl_foo", |
295 // returns the assumed install path. The path separator in |file| is '/' | 295 // returns the assumed install path. The path separator in |file| is '/' |
296 // for all platforms. Caller is responsible for checking that the | 296 // for all platforms. Caller is responsible for checking that the |
297 // |installed_file| actually exists. | 297 // |installed_file| actually exists. |
298 bool PnaclComponentInstaller::GetInstalledFile( | 298 bool PnaclComponentInstaller::GetInstalledFile( |
299 const std::string& file, base::FilePath* installed_file) { | 299 const std::string& file, base::FilePath* installed_file) { |
300 if (current_version().Equals(base::Version(kNullVersion))) | 300 if (current_version().Equals(Version(kNullVersion))) |
301 return false; | 301 return false; |
302 | 302 |
303 *installed_file = GetPnaclBaseDirectory().AppendASCII( | 303 *installed_file = GetPnaclBaseDirectory().AppendASCII( |
304 current_version().GetString()).AppendASCII(file); | 304 current_version().GetString()).AppendASCII(file); |
305 return true; | 305 return true; |
306 } | 306 } |
307 | 307 |
308 CrxComponent PnaclComponentInstaller::GetCrxComponent() { | 308 CrxComponent PnaclComponentInstaller::GetCrxComponent() { |
309 CrxComponent pnacl_component; | 309 CrxComponent pnacl_component; |
310 pnacl_component.version = current_version(); | 310 pnacl_component.version = current_version(); |
311 pnacl_component.name = "pnacl"; | 311 pnacl_component.name = "pnacl"; |
312 pnacl_component.installer = this; | 312 pnacl_component.installer = this; |
313 pnacl_component.fingerprint = current_fingerprint(); | 313 pnacl_component.fingerprint = current_fingerprint(); |
314 SetPnaclHash(&pnacl_component); | 314 SetPnaclHash(&pnacl_component); |
315 | 315 |
316 return pnacl_component; | 316 return pnacl_component; |
317 } | 317 } |
318 | 318 |
319 namespace { | 319 namespace { |
320 | 320 |
321 void FinishPnaclUpdateRegistration(const base::Version& current_version, | 321 void FinishPnaclUpdateRegistration(const Version& current_version, |
322 const std::string& current_fingerprint, | 322 const std::string& current_fingerprint, |
323 PnaclComponentInstaller* pci) { | 323 PnaclComponentInstaller* pci) { |
324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
325 pci->set_current_version(current_version); | 325 pci->set_current_version(current_version); |
326 CheckVersionCompatiblity(current_version); | 326 CheckVersionCompatiblity(current_version); |
327 pci->set_current_fingerprint(current_fingerprint); | 327 pci->set_current_fingerprint(current_fingerprint); |
328 CrxComponent pnacl_component = pci->GetCrxComponent(); | 328 CrxComponent pnacl_component = pci->GetCrxComponent(); |
329 | 329 |
330 ComponentUpdateService::Status status = | 330 ComponentUpdateService::Status status = |
331 pci->cus()->RegisterComponent(pnacl_component); | 331 pci->cus()->RegisterComponent(pnacl_component); |
332 if (status != ComponentUpdateService::kOk | 332 if (status != ComponentUpdateService::kOk |
333 && status != ComponentUpdateService::kReplaced) { | 333 && status != ComponentUpdateService::kReplaced) { |
334 NOTREACHED() << "Pnacl component registration failed."; | 334 NOTREACHED() << "Pnacl component registration failed."; |
335 } | 335 } |
336 } | 336 } |
337 | 337 |
338 // Check if there is an existing version on disk first to know when | 338 // Check if there is an existing version on disk first to know when |
339 // a hosted version is actually newer. | 339 // a hosted version is actually newer. |
340 void StartPnaclUpdateRegistration(PnaclComponentInstaller* pci) { | 340 void StartPnaclUpdateRegistration(PnaclComponentInstaller* pci) { |
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
342 base::FilePath path = pci->GetPnaclBaseDirectory(); | 342 base::FilePath path = pci->GetPnaclBaseDirectory(); |
343 if (!base::PathExists(path)) { | 343 if (!base::PathExists(path)) { |
344 if (!base::CreateDirectory(path)) { | 344 if (!base::CreateDirectory(path)) { |
345 NOTREACHED() << "Could not create base Pnacl directory."; | 345 NOTREACHED() << "Could not create base Pnacl directory."; |
346 return; | 346 return; |
347 } | 347 } |
348 } | 348 } |
349 | 349 |
350 base::Version current_version(kNullVersion); | 350 Version current_version(kNullVersion); |
351 std::string current_fingerprint; | 351 std::string current_fingerprint; |
352 std::vector<base::FilePath> older_dirs; | 352 std::vector<base::FilePath> older_dirs; |
353 if (GetLatestPnaclDirectory(pci, &path, ¤t_version, &older_dirs)) { | 353 if (GetLatestPnaclDirectory(pci, &path, ¤t_version, &older_dirs)) { |
354 scoped_ptr<base::DictionaryValue> manifest( | 354 scoped_ptr<base::DictionaryValue> manifest( |
355 ReadComponentManifest(path)); | 355 ReadComponentManifest(path)); |
356 scoped_ptr<base::DictionaryValue> pnacl_manifest( | 356 scoped_ptr<base::DictionaryValue> pnacl_manifest( |
357 ReadPnaclManifest(path)); | 357 ReadPnaclManifest(path)); |
358 base::Version manifest_version; | 358 Version manifest_version; |
359 // Check that the component manifest and PNaCl manifest files | 359 // Check that the component manifest and PNaCl manifest files |
360 // are legit, and that the indicated version matches the one | 360 // are legit, and that the indicated version matches the one |
361 // encoded within the path name. | 361 // encoded within the path name. |
362 if (manifest == NULL || pnacl_manifest == NULL | 362 if (manifest == NULL || pnacl_manifest == NULL |
363 || !CheckPnaclComponentManifest(*manifest, | 363 || !CheckPnaclComponentManifest(*manifest, |
364 *pnacl_manifest, | 364 *pnacl_manifest, |
365 &manifest_version) | 365 &manifest_version) |
366 || !current_version.Equals(manifest_version)) { | 366 || !current_version.Equals(manifest_version)) { |
367 current_version = base::Version(kNullVersion); | 367 current_version = Version(kNullVersion); |
368 } else { | 368 } else { |
369 OverrideDirPnaclComponent(path); | 369 OverrideDirPnaclComponent(path); |
370 base::ReadFileToString(path.AppendASCII("manifest.fingerprint"), | 370 base::ReadFileToString(path.AppendASCII("manifest.fingerprint"), |
371 ¤t_fingerprint); | 371 ¤t_fingerprint); |
372 } | 372 } |
373 } | 373 } |
374 | 374 |
375 // If updates are disabled, only discover the current version | 375 // If updates are disabled, only discover the current version |
376 // and OverrideDirPnaclComponent. That way, developers can use | 376 // and OverrideDirPnaclComponent. That way, developers can use |
377 // a pinned version. Do not actually finish registration with | 377 // a pinned version. Do not actually finish registration with |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 } | 456 } |
457 | 457 |
458 | 458 |
459 namespace pnacl { | 459 namespace pnacl { |
460 | 460 |
461 bool NeedsOnDemandUpdate() { | 461 bool NeedsOnDemandUpdate() { |
462 return base::subtle::NoBarrier_Load(&needs_on_demand_update) != 0; | 462 return base::subtle::NoBarrier_Load(&needs_on_demand_update) != 0; |
463 } | 463 } |
464 | 464 |
465 } // namespace pnacl | 465 } // namespace pnacl |
OLD | NEW |