Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: chrome/browser/component_updater/pnacl/pnacl_component_installer.cc

Issue 13071002: Turn on component updater on chromeos, only for the pnacl component. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: debug Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "chrome/common/omaha_query_params.h" 27 #include "chrome/common/omaha_query_params.h"
25 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/browser_thread.h"
26 29
27 using chrome::OmahaQueryParams; 30 using chrome::OmahaQueryParams;
28 using content::BrowserThread; 31 using content::BrowserThread;
29 32
30 namespace { 33 namespace {
31 34
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 &mips32_sha256_hash[sizeof(mips32_sha256_hash)]); 112 &mips32_sha256_hash[sizeof(mips32_sha256_hash)]);
110 #else 113 #else
111 #error "Add support for your architecture to Pnacl Component Installer." 114 #error "Add support for your architecture to Pnacl Component Installer."
112 #endif 115 #endif
113 } 116 }
114 117
115 118
116 // If we don't have Pnacl installed, this is the version we claim. 119 // If we don't have Pnacl installed, this is the version we claim.
117 const char kNullVersion[] = "0.0.0.0"; 120 const char kNullVersion[] = "0.0.0.0";
118 121
119 // Pnacl components have the version encoded in the path itself: 122 bool GetLatestPnaclDirectory(PnaclComponentInstaller* pci,
120 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\0.1.2.3\. 123 base::FilePath* latest_dir,
121 // and the base directory will be:
122 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\.
123 base::FilePath GetPnaclBaseDirectory() {
124 base::FilePath result;
125 CHECK(PathService::Get(chrome::DIR_PNACL_BASE, &result));
126 return result;
127 }
128
129 bool GetLatestPnaclDirectory(base::FilePath* latest_dir,
130 Version* latest_version, 124 Version* latest_version,
131 std::vector<base::FilePath>* older_dirs) { 125 std::vector<base::FilePath>* older_dirs) {
132 // Enumerate all versions starting from the base directory. 126 // Enumerate all versions starting from the base directory.
133 base::FilePath base_dir = GetPnaclBaseDirectory(); 127 base::FilePath base_dir = pci->GetPnaclBaseDirectory();
134 bool found = false; 128 bool found = false;
135 file_util::FileEnumerator 129 file_util::FileEnumerator
136 file_enumerator(base_dir, false, file_util::FileEnumerator::DIRECTORIES); 130 file_enumerator(base_dir, false, file_util::FileEnumerator::DIRECTORIES);
137 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); 131 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
138 path = file_enumerator.Next()) { 132 path = file_enumerator.Next()) {
139 Version version(path.BaseName().MaybeAsASCII()); 133 Version version(path.BaseName().MaybeAsASCII());
140 if (!version.IsValid()) 134 if (!version.IsValid())
141 continue; 135 continue;
142 if (found) { 136 if (found) {
143 if (version.CompareTo(*latest_version) > 0) { 137 if (version.CompareTo(*latest_version) > 0) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 if (arch.compare(OmahaQueryParams::getNaclArch()) != 0) { 197 if (arch.compare(OmahaQueryParams::getNaclArch()) != 0) {
204 LOG(WARNING) << "'pnacl-arch' field in manifest is invalid (" 198 LOG(WARNING) << "'pnacl-arch' field in manifest is invalid ("
205 << arch << " vs " << OmahaQueryParams::getNaclArch() << ")"; 199 << arch << " vs " << OmahaQueryParams::getNaclArch() << ")";
206 return false; 200 return false;
207 } 201 }
208 202
209 *version_out = version; 203 *version_out = version;
210 return true; 204 return true;
211 } 205 }
212 206
213 class PnaclComponentInstaller : public ComponentInstaller { 207 PnaclComponentInstaller::PnaclComponentInstaller()
214 public: 208 : per_user_(false),
215 explicit PnaclComponentInstaller(const Version& version); 209 cus_(NULL) {
210 #if defined(OS_CHROMEOS)
211 per_user_ = true;
212 #endif
213 }
216 214
217 virtual ~PnaclComponentInstaller() {} 215 PnaclComponentInstaller::~PnaclComponentInstaller() {
218
219 virtual void OnUpdateError(int error) OVERRIDE;
220
221 virtual bool Install(base::DictionaryValue* manifest,
222 const base::FilePath& unpack_path) OVERRIDE;
223
224 private:
225 Version current_version_;
226 };
227
228 PnaclComponentInstaller::PnaclComponentInstaller(
229 const Version& version) : current_version_(version) {
230 DCHECK(version.IsValid());
231 } 216 }
232 217
233 void PnaclComponentInstaller::OnUpdateError(int error) { 218 void PnaclComponentInstaller::OnUpdateError(int error) {
234 NOTREACHED() << "Pnacl update error: " << error; 219 NOTREACHED() << "Pnacl update error: " << error;
235 } 220 }
236 221
222 // Pnacl components have the version encoded in the path itself:
223 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\0.1.2.3\.
224 // and the base directory will be:
225 // <profile>\AppData\Local\Google\Chrome\User Data\Pnacl\.
226 base::FilePath PnaclComponentInstaller::GetPnaclBaseDirectory() {
227 // For ChromeOS, temporarily make this user-dependent (for integrity) until
228 // we find a better solution.
229 // This is not ideal because of the following:
230 // (a) We end up with per-user copies instead of a single copy
231 // (b) The profile can change as users log in to different accounts
232 // so we need to watch for user-login-events (see pnacl_profile_observer.h).
233 if (per_user_) {
234 DCHECK(!current_profile_path_.empty());
235 base::FilePath path = current_profile_path_.Append(
236 FILE_PATH_LITERAL("pnacl"));
237 return path;
238 } else {
239 base::FilePath result;
240 CHECK(PathService::Get(chrome::DIR_PNACL_BASE, &result));
241 return result;
242 }
243 }
244
245 void PnaclComponentInstaller::OnProfileChange() {
246 // On chromeos, we want to find the --login-profile=<foo> dir.
247 // Even though the path does vary between users, the content
248 // changes when logging out and logging in.
249 ProfileManager* pm = g_browser_process->profile_manager();
250 current_profile_path_ = pm->user_data_dir().Append(
251 pm->GetInitialProfileDir());
252 }
253
237 namespace { 254 namespace {
238 255
239 bool PathContainsPnacl(const base::FilePath& base_path) { 256 bool PathContainsPnacl(const base::FilePath& base_path) {
240 // Check that at least one of the compiler files exists, for the current ISA. 257 // Check that at least one of the compiler files exists, for the current ISA.
241 std::string expected_filename("pnacl_public_"); 258 std::string expected_filename("pnacl_public_");
242 std::string arch = OmahaQueryParams::getNaclArch(); 259 std::string arch = OmahaQueryParams::getNaclArch();
243 expected_filename = expected_filename + SanitizeForPath(arch) + 260 expected_filename = expected_filename + SanitizeForPath(arch) +
244 "_" + kPnaclCompilerFileName; 261 "_" + kPnaclCompilerFileName;
245 return file_util::PathExists(base_path.AppendASCII(expected_filename)); 262 return file_util::PathExists(base_path.AppendASCII(expected_filename));
246 } 263 }
(...skipping 11 matching lines...) Expand all
258 275
259 Version version; 276 Version version;
260 if (!CheckPnaclComponentManifest(manifest, 277 if (!CheckPnaclComponentManifest(manifest,
261 pnacl_manifest.get(), 278 pnacl_manifest.get(),
262 &version)) { 279 &version)) {
263 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing."; 280 LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing.";
264 return false; 281 return false;
265 } 282 }
266 283
267 // Don't install if the current version is actually newer. 284 // Don't install if the current version is actually newer.
268 if (current_version_.CompareTo(version) > 0) 285 if (current_version().CompareTo(version) > 0)
269 return false; 286 return false;
270 287
271 if (!PathContainsPnacl(unpack_path)) { 288 if (!PathContainsPnacl(unpack_path)) {
272 LOG(WARNING) << "PathContainsPnacl check failed, not installing."; 289 LOG(WARNING) << "PathContainsPnacl check failed, not installing.";
273 return false; 290 return false;
274 } 291 }
275 292
276 // Passed the basic tests. Time to install it. 293 // Passed the basic tests. Time to install it.
277 base::FilePath path = 294 base::FilePath path = GetPnaclBaseDirectory().AppendASCII(
278 GetPnaclBaseDirectory().AppendASCII(version.GetString()); 295 version.GetString());
279 if (file_util::PathExists(path)) { 296 if (file_util::PathExists(path)) {
280 LOG(WARNING) << "Target path already exists, not installing."; 297 LOG(WARNING) << "Target path already exists, not installing.";
281 return false; 298 return false;
282 } 299 }
283 if (!file_util::Move(unpack_path, path)) { 300 if (!file_util::Move(unpack_path, path)) {
284 LOG(WARNING) << "Move failed, not installing."; 301 LOG(WARNING) << "Move failed, not installing.";
285 return false; 302 return false;
286 } 303 }
287 304
288 // Installation is done. Now tell the rest of chrome (just the path service 305 // Installation is done. Now tell the rest of chrome (just the path service
289 // for now). TODO(jvoung): we need notifications if someone surfed to a 306 // for now). TODO(jvoung): we need notifications if someone surfed to a
290 // Pnacl webpage and Pnacl was just installed at this time. They should 307 // Pnacl webpage and Pnacl was just installed at this time. They should
291 // then be able to reload the page and retry (or something). 308 // then be able to reload the page and retry (or something).
292 // See: http://code.google.com/p/chromium/issues/detail?id=107438 309 // See: http://code.google.com/p/chromium/issues/detail?id=107438
293 current_version_ = version; 310 set_current_version(version);
294 311
295 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); 312 PathService::Override(chrome::DIR_PNACL_COMPONENT, path);
296 return true; 313 return true;
297 } 314 }
298 315
299 namespace { 316 namespace {
300 317
301 void DoCheckForUpdate(ComponentUpdateService* cus, 318 void DoCheckForUpdate(ComponentUpdateService* cus,
302 const CrxComponent& pnacl) { 319 const CrxComponent& pnacl) {
303 if (cus->CheckForUpdateSoon(pnacl) != ComponentUpdateService::kOk) { 320 if (cus->CheckForUpdateSoon(pnacl) != ComponentUpdateService::kOk) {
304 LOG(WARNING) << "Pnacl check for update failed."; 321 LOG(WARNING) << "Pnacl check for update failed.";
305 } 322 }
306 } 323 }
307 324
308 // Finally, do the registration with the right version number. 325 // Finally, do the registration with the right version number.
309 void FinishPnaclUpdateRegistration(ComponentUpdateService* cus, 326 void FinishPnaclUpdateRegistration(const Version& current_version,
310 const Version& current_version) { 327 PnaclComponentInstaller* pci) {
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312 // Note: the source is the default of BANDAID, even though the 329 CrxComponent pnacl_component;
313 // crxes are hosted from CWS. 330 pnacl_component.version = current_version;
314 CrxComponent pnacl; 331 pnacl_component.name = "pnacl";
315 pnacl.name = "pnacl"; 332 pnacl_component.installer = pci;
316 pnacl.installer = new PnaclComponentInstaller(current_version); 333 pci->set_current_version(current_version);
317 pnacl.version = current_version; 334 SetPnaclHash(&pnacl_component);
318 SetPnaclHash(&pnacl); 335
319 if (cus->RegisterComponent(pnacl) != ComponentUpdateService::kOk) { 336 ComponentUpdateService::Status status =
337 pci->cus()->RegisterComponent(pnacl_component);
338 if (status != ComponentUpdateService::kOk
339 && status != ComponentUpdateService::kReplaced) {
320 NOTREACHED() << "Pnacl component registration failed."; 340 NOTREACHED() << "Pnacl component registration failed.";
321 } 341 }
322 342
323 // If PNaCl is not yet installed but it is requested by --enable-pnacl, 343 // If PNaCl is not yet installed but it is requested by --enable-pnacl,
324 // we want it to be available "soon", so kick off an update check 344 // we want it to be available "soon", so kick off an update check
325 // earlier than usual. 345 // earlier than usual.
326 Version null_version(kNullVersion); 346 Version null_version(kNullVersion);
327 if (current_version.Equals(null_version)) { 347 if (pci->current_version().Equals(null_version)) {
328 BrowserThread::PostDelayedTask( 348 BrowserThread::PostDelayedTask(
329 BrowserThread::UI, FROM_HERE, 349 BrowserThread::UI, FROM_HERE,
330 base::Bind(DoCheckForUpdate, cus, pnacl), 350 base::Bind(DoCheckForUpdate, pci->cus(), pnacl_component),
331 base::TimeDelta::FromSeconds(kInitialDelaySeconds)); 351 base::TimeDelta::FromSeconds(kInitialDelaySeconds));
332 } 352 }
333 } 353 }
334 354
335 // Check if there is an existing version on disk first to know when 355 // Check if there is an existing version on disk first to know when
336 // a hosted version is actually newer. 356 // a hosted version is actually newer.
337 void StartPnaclUpdateRegistration(ComponentUpdateService* cus) { 357 void StartPnaclUpdateRegistration(PnaclComponentInstaller* pci) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
339 base::FilePath path = GetPnaclBaseDirectory(); 359 base::FilePath path = pci->GetPnaclBaseDirectory();
340 if (!file_util::PathExists(path)) { 360 if (!file_util::PathExists(path)) {
341 if (!file_util::CreateDirectory(path)) { 361 if (!file_util::CreateDirectory(path)) {
342 NOTREACHED() << "Could not create base Pnacl directory."; 362 NOTREACHED() << "Could not create base Pnacl directory.";
343 return; 363 return;
344 } 364 }
345 } 365 }
346 366
347 Version version(kNullVersion); 367 Version version(kNullVersion);
348 std::vector<base::FilePath> older_dirs; 368 std::vector<base::FilePath> older_dirs;
349 if (GetLatestPnaclDirectory(&path, &version, &older_dirs)) { 369 if (GetLatestPnaclDirectory(pci, &path, &version, &older_dirs)) {
350 if (!PathContainsPnacl(path)) { 370 if (!PathContainsPnacl(path)) {
351 version = Version(kNullVersion); 371 version = Version(kNullVersion);
352 } else { 372 } else {
353 PathService::Override(chrome::DIR_PNACL_COMPONENT, path); 373 PathService::Override(chrome::DIR_PNACL_COMPONENT, path);
354 } 374 }
355 } 375 }
356 376
357 BrowserThread::PostTask( 377 BrowserThread::PostTask(
358 BrowserThread::UI, FROM_HERE, 378 BrowserThread::UI, FROM_HERE,
359 base::Bind(&FinishPnaclUpdateRegistration, cus, version)); 379 base::Bind(&FinishPnaclUpdateRegistration, version, pci));
360 380
361 // Remove older versions of PNaCl. 381 // Remove older versions of PNaCl.
362 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin(); 382 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
363 iter != older_dirs.end(); ++iter) { 383 iter != older_dirs.end(); ++iter) {
364 file_util::Delete(*iter, true); 384 file_util::Delete(*iter, true);
365 } 385 }
366 } 386 }
367 387
388 void GetProfileInformation(PnaclComponentInstaller* pci) {
389 // Bail if not logged in yet.
390 if (!g_browser_process->profile_manager()->IsLoggedIn()) {
391 return;
392 }
393
394 pci->OnProfileChange();
395
396 BrowserThread::PostTask(
397 BrowserThread::FILE, FROM_HERE,
398 base::Bind(&StartPnaclUpdateRegistration, pci));
399 }
400
401
368 } // namespace 402 } // namespace
369 403
370 void RegisterPnaclComponent(ComponentUpdateService* cus, 404 void PnaclComponentInstaller::RegisterPnaclComponent(
405 ComponentUpdateService* cus,
371 const CommandLine& command_line) { 406 const CommandLine& command_line) {
372 // Only register when given the right flag. This is important since 407 // Only register when given the right flag. This is important since
373 // we do an early component updater check above (in DoCheckForUpdate). 408 // we do an early component updater check above (in DoCheckForUpdate).
374 if (command_line.HasSwitch(switches::kEnablePnacl)) { 409 if (command_line.HasSwitch(switches::kEnablePnacl)) {
375 BrowserThread::PostTask( 410 cus_ = cus;
376 BrowserThread::FILE, FROM_HERE, 411 // If per_user, create a profile observer to watch for logins.
377 base::Bind(&StartPnaclUpdateRegistration, cus)); 412 // Only do so after cus_ is set to something non-null.
413 if (per_user_ && !profile_observer_) {
414 profile_observer_.reset(new PnaclProfileObserver(this));
415 }
416 if (per_user_) {
417 // Figure out profile information, before proceeding to look for files.
418 BrowserThread::PostTask(
419 BrowserThread::UI, FROM_HERE,
420 base::Bind(&GetProfileInformation, this));
421 } else {
422 BrowserThread::PostTask(
423 BrowserThread::FILE, FROM_HERE,
424 base::Bind(&StartPnaclUpdateRegistration, this));
425 }
378 } 426 }
379 } 427 }
428
429 void PnaclComponentInstaller::ReRegisterPnacl() {
430 // No need to check the commandline flags again here.
431 // We could only have gotten here after RegisterPnaclComponent
432 // found --enable-pnacl, since that is where we create the profile_observer_,
433 // which in turn calls ReRegisterPnacl.
434 DCHECK(per_user_);
435 // Figure out profile information, before proceeding to look for files.
436 BrowserThread::PostTask(
437 BrowserThread::UI, FROM_HERE,
438 base::Bind(&GetProfileInformation, this));
439 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698