Chromium Code Reviews| 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/base_paths.h" | 7 #include "base/base_paths.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/json/json_file_value_serializer.h" | 13 #include "base/json/json_file_value_serializer.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/path_service.h" | 15 #include "base/path_service.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/values.h" | 17 #include "base/values.h" |
| 18 #include "base/version.h" | 18 #include "base/version.h" |
| 19 #include "base/win/windows_version.h" | 19 #include "base/win/windows_version.h" |
| 20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 21 #include "chrome/browser/browser_process.h" | |
| 21 #include "chrome/browser/component_updater/component_updater_service.h" | 22 #include "chrome/browser/component_updater/component_updater_service.h" |
| 23 #include "chrome/browser/profiles/profile.h" | |
| 24 #include "chrome/browser/profiles/profile_manager.h" | |
| 22 #include "chrome/common/chrome_paths.h" | 25 #include "chrome/common/chrome_paths.h" |
| 23 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
| 24 #include "content/public/browser/browser_thread.h" | 27 #include "content/public/browser/browser_thread.h" |
| 25 | 28 |
| 26 using content::BrowserThread; | 29 using content::BrowserThread; |
| 27 | 30 |
| 28 namespace { | 31 namespace { |
| 29 | 32 |
| 30 // If PNaCl isn't installed yet, but a user is running chrome with | 33 // If PNaCl isn't installed yet, but a user is running chrome with |
| 31 // --enable-pnacl, this is the amount of time to wait before starting | 34 // --enable-pnacl, this is the amount of time to wait before starting |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 | 137 |
| 135 | 138 |
| 136 // If we don't have Pnacl installed, this is the version we claim. | 139 // If we don't have Pnacl installed, this is the version we claim. |
| 137 const char kNullVersion[] = "0.0.0.0"; | 140 const char kNullVersion[] = "0.0.0.0"; |
| 138 | 141 |
| 139 // Pnacl components have the version encoded in the path itself: | 142 // Pnacl components have the version encoded in the path itself: |
| 140 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\0.1.2.3\. | 143 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\0.1.2.3\. |
| 141 // and the base directory will be: | 144 // and the base directory will be: |
| 142 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\. | 145 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\. |
| 143 base::FilePath GetPnaclBaseDirectory() { | 146 base::FilePath GetPnaclBaseDirectory() { |
| 147 #if defined(OS_CHROMEOS) | |
| 148 // For ChromeOS, temporarily make this user-dependent (for integrity) until | |
| 149 // we find a better solution. | |
| 150 // This is not ideal because of the following: | |
| 151 // (a) We end up with per-user copies instead of a single copy | |
| 152 // (b) The profile can change as users log in to different accounts | |
| 153 // so we need to watch for user-login-events (see pnacl_profile_observer.h). | |
| 154 Profile* profile = ProfileManager::GetLastUsedProfile(); | |
| 155 base::FilePath path = profile->GetPath().AppendASCII( | |
| 156 FILE_PATH_LITERAL("pnacl")); | |
|
Dmitry Polukhin
2013/03/26 11:59:56
Nit, 2 idents.
jvoung - send to chromium...
2013/03/26 15:46:53
Done.
| |
| 157 return path; | |
| 158 #else | |
| 144 base::FilePath result; | 159 base::FilePath result; |
| 145 CHECK(PathService::Get(chrome::DIR_PNACL_BASE, &result)); | 160 CHECK(PathService::Get(chrome::DIR_PNACL_BASE, &result)); |
| 146 return result; | 161 return result; |
| 162 #endif | |
| 147 } | 163 } |
| 148 | 164 |
| 149 bool GetLatestPnaclDirectory(base::FilePath* latest_dir, | 165 bool GetLatestPnaclDirectory(base::FilePath* latest_dir, |
| 150 Version* latest_version, | 166 Version* latest_version, |
| 151 std::vector<base::FilePath>* older_dirs) { | 167 std::vector<base::FilePath>* older_dirs) { |
| 152 // Enumerate all versions starting from the base directory. | 168 // Enumerate all versions starting from the base directory. |
| 153 base::FilePath base_dir = GetPnaclBaseDirectory(); | 169 base::FilePath base_dir = GetPnaclBaseDirectory(); |
| 154 bool found = false; | 170 bool found = false; |
| 155 file_util::FileEnumerator | 171 file_util::FileEnumerator |
| 156 file_enumerator(base_dir, false, file_util::FileEnumerator::DIRECTORIES); | 172 file_enumerator(base_dir, false, file_util::FileEnumerator::DIRECTORIES); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 if (arch.compare(PnaclArch()) != 0) { | 239 if (arch.compare(PnaclArch()) != 0) { |
| 224 LOG(WARNING) << "'pnacl-arch' field in manifest is invalid (" | 240 LOG(WARNING) << "'pnacl-arch' field in manifest is invalid (" |
| 225 << arch << " vs " << PnaclArch() << ")"; | 241 << arch << " vs " << PnaclArch() << ")"; |
| 226 return false; | 242 return false; |
| 227 } | 243 } |
| 228 | 244 |
| 229 *version_out = version; | 245 *version_out = version; |
| 230 return true; | 246 return true; |
| 231 } | 247 } |
| 232 | 248 |
| 233 class PnaclComponentInstaller : public ComponentInstaller { | 249 PnaclComponentInstaller::PnaclComponentInstaller() : cus_(NULL) { |
| 234 public: | 250 // Fill in most of the information. The version will be discovered later. |
| 235 explicit PnaclComponentInstaller(const Version& version); | 251 Version null_version(kNullVersion); |
| 252 pnacl_component_.version = null_version; | |
| 253 pnacl_component_.name = "pnacl"; | |
| 254 pnacl_component_.installer = this; | |
| 255 SetPnaclHash(&pnacl_component_); | |
| 236 | 256 |
| 237 virtual ~PnaclComponentInstaller() {} | 257 #if defined(OS_CHROMEOS) |
| 258 profile_observer_.reset(new PnaclProfileObserver(this)); | |
| 259 #endif | |
| 260 } | |
| 238 | 261 |
| 239 virtual void OnUpdateError(int error) OVERRIDE; | 262 PnaclComponentInstaller::~PnaclComponentInstaller() { |
| 240 | |
| 241 virtual bool Install(base::DictionaryValue* manifest, | |
| 242 const base::FilePath& unpack_path) OVERRIDE; | |
| 243 | |
| 244 private: | |
| 245 Version current_version_; | |
| 246 }; | |
| 247 | |
| 248 PnaclComponentInstaller::PnaclComponentInstaller( | |
| 249 const Version& version) : current_version_(version) { | |
| 250 DCHECK(version.IsValid()); | |
| 251 } | 263 } |
| 252 | 264 |
| 253 void PnaclComponentInstaller::OnUpdateError(int error) { | 265 void PnaclComponentInstaller::OnUpdateError(int error) { |
| 254 NOTREACHED() << "Pnacl update error: " << error; | 266 NOTREACHED() << "Pnacl update error: " << error; |
| 255 } | 267 } |
| 256 | 268 |
| 257 namespace { | 269 namespace { |
| 258 | 270 |
| 259 bool PathContainsPnacl(const base::FilePath& base_path) { | 271 bool PathContainsPnacl(const base::FilePath& base_path) { |
| 260 // Check that at least one of the compiler files exists, for the current ISA. | 272 // Check that at least one of the compiler files exists, for the current ISA. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 278 | 290 |
| 279 Version version; | 291 Version version; |
| 280 if (!CheckPnaclComponentManifest(manifest, | 292 if (!CheckPnaclComponentManifest(manifest, |
| 281 pnacl_manifest.get(), | 293 pnacl_manifest.get(), |
| 282 &version)) { | 294 &version)) { |
| 283 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing."; | 295 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing."; |
| 284 return false; | 296 return false; |
| 285 } | 297 } |
| 286 | 298 |
| 287 // Don't install if the current version is actually newer. | 299 // Don't install if the current version is actually newer. |
| 288 if (current_version_.CompareTo(version) > 0) | 300 if (get_current_version().CompareTo(version) > 0) |
| 289 return false; | 301 return false; |
| 290 | 302 |
| 291 if (!PathContainsPnacl(unpack_path)) { | 303 if (!PathContainsPnacl(unpack_path)) { |
| 292 LOG(WARNING) << "PathContainsPnacl check failed, not installing."; | 304 LOG(WARNING) << "PathContainsPnacl check failed, not installing."; |
| 293 return false; | 305 return false; |
| 294 } | 306 } |
| 295 | 307 |
| 296 // Passed the basic tests. Time to install it. | 308 // Passed the basic tests. Time to install it. |
| 297 base::FilePath path = | 309 base::FilePath path = |
| 298 GetPnaclBaseDirectory().AppendASCII(version.GetString()); | 310 GetPnaclBaseDirectory().AppendASCII(version.GetString()); |
| 299 if (file_util::PathExists(path)) { | 311 if (file_util::PathExists(path)) { |
| 300 LOG(WARNING) << "Target path already exists, not installing."; | 312 LOG(WARNING) << "Target path already exists, not installing."; |
| 301 return false; | 313 return false; |
| 302 } | 314 } |
| 303 if (!file_util::Move(unpack_path, path)) { | 315 if (!file_util::Move(unpack_path, path)) { |
| 304 LOG(WARNING) << "Move failed, not installing."; | 316 LOG(WARNING) << "Move failed, not installing."; |
| 305 return false; | 317 return false; |
| 306 } | 318 } |
| 307 | 319 |
| 308 // Installation is done. Now tell the rest of chrome (just the path service | 320 // Installation is done. Now tell the rest of chrome (just the path service |
| 309 // for now). TODO(jvoung): we need notifications if someone surfed to a | 321 // for now). TODO(jvoung): we need notifications if someone surfed to a |
| 310 // Pnacl webpage and Pnacl was just installed at this time. They should | 322 // Pnacl webpage and Pnacl was just installed at this time. They should |
| 311 // then be able to reload the page and retry (or something). | 323 // then be able to reload the page and retry (or something). |
| 312 // See: http://code.google.com/p/chromium/issues/detail?id=107438 | 324 // See: http://code.google.com/p/chromium/issues/detail?id=107438 |
| 313 current_version_ = version; | 325 set_current_version(version); |
| 314 | 326 |
| 315 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); | 327 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); |
| 316 return true; | 328 return true; |
| 317 } | 329 } |
| 318 | 330 |
| 319 namespace { | 331 namespace { |
| 320 | 332 |
| 321 void DoCheckForUpdate(ComponentUpdateService* cus, | 333 void DoCheckForUpdate(ComponentUpdateService* cus, |
| 322 const CrxComponent& pnacl) { | 334 const CrxComponent& pnacl) { |
| 323 if (cus->CheckForUpdateSoon(pnacl) != ComponentUpdateService::kOk) { | 335 if (cus->CheckForUpdateSoon(pnacl) != ComponentUpdateService::kOk) { |
| 324 LOG(WARNING) << "Pnacl check for update failed."; | 336 LOG(WARNING) << "Pnacl check for update failed."; |
| 325 } | 337 } |
| 326 } | 338 } |
| 327 | 339 |
| 328 // Finally, do the registration with the right version number. | 340 // Finally, do the registration with the right version number. |
| 329 void FinishPnaclUpdateRegistration(ComponentUpdateService* cus, | 341 void FinishPnaclUpdateRegistration(ComponentUpdateService* cus, |
| 330 const Version& current_version) { | 342 PnaclComponentInstaller* pci) { |
| 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 332 // Note: the source is the default of BANDAID, even though the | 344 CrxComponent pnacl_component = pci->get_component(); |
| 333 // crxes are hosted from CWS. | 345 ComponentUpdateService::Status status = |
| 334 CrxComponent pnacl; | 346 cus->RegisterComponent(pnacl_component); |
| 335 pnacl.name = "pnacl"; | 347 if (status != ComponentUpdateService::kOk |
| 336 pnacl.installer = new PnaclComponentInstaller(current_version); | 348 && status != ComponentUpdateService::kReplaced) { |
| 337 pnacl.version = current_version; | |
| 338 SetPnaclHash(&pnacl); | |
| 339 if (cus->RegisterComponent(pnacl) != ComponentUpdateService::kOk) { | |
| 340 NOTREACHED() << "Pnacl component registration failed."; | 349 NOTREACHED() << "Pnacl component registration failed."; |
| 341 } | 350 } |
| 342 | 351 |
| 343 // If PNaCl is not yet installed but it is requested by --enable-pnacl, | 352 // If PNaCl is not yet installed but it is requested by --enable-pnacl, |
| 344 // we want it to be available "soon", so kick off an update check | 353 // we want it to be available "soon", so kick off an update check |
| 345 // earlier than usual. | 354 // earlier than usual. |
| 346 Version null_version(kNullVersion); | 355 Version null_version(kNullVersion); |
| 347 if (current_version.Equals(null_version)) { | 356 if (pci->get_current_version().Equals(null_version)) { |
| 348 BrowserThread::PostDelayedTask( | 357 BrowserThread::PostDelayedTask( |
| 349 BrowserThread::UI, FROM_HERE, | 358 BrowserThread::UI, FROM_HERE, |
| 350 base::Bind(DoCheckForUpdate, cus, pnacl), | 359 base::Bind(DoCheckForUpdate, cus, pnacl_component), |
| 351 base::TimeDelta::FromSeconds(kInitialDelaySeconds)); | 360 base::TimeDelta::FromSeconds(kInitialDelaySeconds)); |
| 352 } | 361 } |
| 353 } | 362 } |
| 354 | 363 |
| 355 // Check if there is an existing version on disk first to know when | 364 // Check if there is an existing version on disk first to know when |
| 356 // a hosted version is actually newer. | 365 // a hosted version is actually newer. |
| 357 void StartPnaclUpdateRegistration(ComponentUpdateService* cus) { | 366 void StartPnaclUpdateRegistration(ComponentUpdateService* cus, |
| 367 PnaclComponentInstaller* pci) { | |
| 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 369 #if defined(OS_CHROMEOS) | |
| 370 // For ChromeOS don't start registration until the user has logged in, | |
| 371 // since the files are installed per user. See GetPnaclBaseDirectory(). | |
| 372 if (!g_browser_process->profile_manager()->IsLoggedIn()) | |
| 373 return; | |
| 374 #endif | |
| 359 base::FilePath path = GetPnaclBaseDirectory(); | 375 base::FilePath path = GetPnaclBaseDirectory(); |
| 360 if (!file_util::PathExists(path)) { | 376 if (!file_util::PathExists(path)) { |
| 361 if (!file_util::CreateDirectory(path)) { | 377 if (!file_util::CreateDirectory(path)) { |
| 362 NOTREACHED() << "Could not create base Pnacl directory."; | 378 NOTREACHED() << "Could not create base Pnacl directory."; |
| 363 return; | 379 return; |
| 364 } | 380 } |
| 365 } | 381 } |
| 366 | 382 |
| 367 Version version(kNullVersion); | 383 Version version(kNullVersion); |
| 368 std::vector<base::FilePath> older_dirs; | 384 std::vector<base::FilePath> older_dirs; |
| 369 if (GetLatestPnaclDirectory(&path, &version, &older_dirs)) { | 385 if (GetLatestPnaclDirectory(&path, &version, &older_dirs)) { |
| 370 if (!PathContainsPnacl(path)) { | 386 if (!PathContainsPnacl(path)) { |
| 371 version = Version(kNullVersion); | 387 version = Version(kNullVersion); |
| 372 } else { | 388 } else { |
| 373 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); | 389 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); |
| 374 } | 390 } |
| 375 } | 391 } |
| 376 | 392 |
| 393 pci->set_current_version(version); | |
| 394 | |
| 377 BrowserThread::PostTask( | 395 BrowserThread::PostTask( |
| 378 BrowserThread::UI, FROM_HERE, | 396 BrowserThread::UI, FROM_HERE, |
| 379 base::Bind(&FinishPnaclUpdateRegistration, cus, version)); | 397 base::Bind(&FinishPnaclUpdateRegistration, cus, pci)); |
| 380 | 398 |
| 381 // Remove older versions of PNaCl. | 399 // Remove older versions of PNaCl. |
| 382 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin(); | 400 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin(); |
| 383 iter != older_dirs.end(); ++iter) { | 401 iter != older_dirs.end(); ++iter) { |
| 384 file_util::Delete(*iter, true); | 402 file_util::Delete(*iter, true); |
| 385 } | 403 } |
| 386 } | 404 } |
| 387 | 405 |
| 388 } // namespace | 406 } // namespace |
| 389 | 407 |
| 390 void RegisterPnaclComponent(ComponentUpdateService* cus, | 408 void PnaclComponentInstaller::RegisterPnaclComponent( |
| 409 ComponentUpdateService* cus, | |
| 391 const CommandLine& command_line) { | 410 const CommandLine& command_line) { |
| 392 // Only register when given the right flag. This is important since | 411 // Only register when given the right flag. This is important since |
| 393 // we do an early component updater check above (in DoCheckForUpdate). | 412 // we do an early component updater check above (in DoCheckForUpdate). |
| 394 if (command_line.HasSwitch(switches::kEnablePnacl)) { | 413 if (command_line.HasSwitch(switches::kEnablePnacl)) { |
| 414 cus_ = cus; | |
| 395 BrowserThread::PostTask( | 415 BrowserThread::PostTask( |
| 396 BrowserThread::FILE, FROM_HERE, | 416 BrowserThread::FILE, FROM_HERE, |
| 397 base::Bind(&StartPnaclUpdateRegistration, cus)); | 417 base::Bind(&StartPnaclUpdateRegistration, cus_, this)); |
| 398 } | 418 } |
| 399 } | 419 } |
| 420 | |
| 421 #if defined(OS_CHROMEOS) | |
| 422 void PnaclComponentInstaller::ReRegisterPnacl() { | |
| 423 // We only create the profile observer, which can trigger a | |
| 424 // call to ReRegisterPnacl, if kEnablePnacl is given on the commandline. | |
| 425 // Thus, we don't check the commandline flags again here. | |
| 426 BrowserThread::PostTask( | |
| 427 BrowserThread::FILE, FROM_HERE, | |
| 428 base::Bind(&StartPnaclUpdateRegistration, cus_, this)); | |
| 429 } | |
| 430 #endif | |
| OLD | NEW |