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

Side by Side Diff: chrome/browser/mac/keystone_glue.mm

Issue 1769703002: Add viewing of error messages from Keystone upon self-update failure. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Display errors on status==FAILED, not !message.empty() Created 4 years, 9 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
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 #import "chrome/browser/mac/keystone_glue.h" 5 #import "chrome/browser/mac/keystone_glue.h"
6 6
7 #include <sys/mount.h> 7 #include <sys/mount.h>
8 #include <sys/param.h> 8 #include <sys/param.h>
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 10
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/mac/authorization_util.h" 16 #include "base/mac/authorization_util.h"
17 #include "base/mac/bundle_locations.h" 17 #include "base/mac/bundle_locations.h"
18 #include "base/mac/foundation_util.h" 18 #include "base/mac/foundation_util.h"
19 #include "base/mac/mac_logging.h" 19 #include "base/mac/mac_logging.h"
20 #include "base/mac/scoped_nsautorelease_pool.h" 20 #include "base/mac/scoped_nsautorelease_pool.h"
21 #include "base/memory/ref_counted.h" 21 #include "base/memory/ref_counted.h"
22 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/sys_string_conversions.h" 23 #include "base/strings/sys_string_conversions.h"
23 #include "base/threading/worker_pool.h" 24 #include "base/threading/worker_pool.h"
24 #include "build/build_config.h" 25 #include "build/build_config.h"
25 #import "chrome/browser/mac/keystone_registration.h" 26 #import "chrome/browser/mac/keystone_registration.h"
26 #include "chrome/common/channel_info.h" 27 #include "chrome/common/channel_info.h"
27 #include "chrome/common/chrome_constants.h" 28 #include "chrome/common/chrome_constants.h"
28 #include "chrome/grit/chromium_strings.h" 29 #include "chrome/grit/chromium_strings.h"
29 #include "chrome/grit/generated_resources.h" 30 #include "chrome/grit/generated_resources.h"
30 #include "components/version_info/version_info.h" 31 #include "components/version_info/version_info.h"
31 #include "ui/base/l10n/l10n_util.h" 32 #include "ui/base/l10n/l10n_util.h"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 121
121 // Set the registration active and pass profile count parameters. 122 // Set the registration active and pass profile count parameters.
122 - (void)setRegistrationActive; 123 - (void)setRegistrationActive;
123 124
124 // Called periodically to announce activity by pinging the Keystone server. 125 // Called periodically to announce activity by pinging the Keystone server.
125 - (void)markActive:(NSTimer*)timer; 126 - (void)markActive:(NSTimer*)timer;
126 127
127 // Called when an update check or update installation is complete. Posts the 128 // Called when an update check or update installation is complete. Posts the
128 // kAutoupdateStatusNotification notification to the default notification 129 // kAutoupdateStatusNotification notification to the default notification
129 // center. 130 // center.
130 - (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version; 131 - (void)updateStatus:(AutoupdateStatus)status
132 version:(NSString*)version
133 error:(NSString*)error;
131 134
132 // Returns the version of the currently-installed application on disk. 135 // Returns the version of the currently-installed application on disk.
133 - (NSString*)currentlyInstalledVersion; 136 - (NSString*)currentlyInstalledVersion;
134 137
135 // These three methods are used to determine the version of the application 138 // These three methods are used to determine the version of the application
136 // currently installed on disk, compare that to the currently-running version, 139 // currently installed on disk, compare that to the currently-running version,
137 // decide whether any updates have been installed, and call 140 // decide whether any updates have been installed, and call
138 // -updateStatus:version:. 141 // -updateStatus:version:error:.
139 // 142 //
140 // In order to check the version on disk, the installed application's 143 // In order to check the version on disk, the installed application's
141 // Info.plist dictionary must be read; in order to see changes as updates are 144 // Info.plist dictionary must be read; in order to see changes as updates are
142 // applied, the dictionary must be read each time, bypassing any caches such 145 // applied, the dictionary must be read each time, bypassing any caches such
143 // as the one that NSBundle might be maintaining. Reading files can be a 146 // as the one that NSBundle might be maintaining. Reading files can be a
144 // blocking operation, and blocking operations are to be avoided on the main 147 // blocking operation, and blocking operations are to be avoided on the main
145 // thread. I'm not quite sure what jank means, but I bet that a blocked main 148 // thread. I'm not quite sure what jank means, but I bet that a blocked main
146 // thread would cause some of it. 149 // thread would cause some of it.
147 // 150 //
148 // -determineUpdateStatusAsync is called on the main thread to initiate the 151 // -determineUpdateStatusAsync is called on the main thread to initiate the
149 // operation. It performs initial set-up work that must be done on the main 152 // operation. It performs initial set-up work that must be done on the main
150 // thread and arranges for -determineUpdateStatus to be called on a work queue 153 // thread and arranges for -determineUpdateStatus to be called on a work queue
151 // thread managed by WorkerPool. 154 // thread managed by WorkerPool.
152 // -determineUpdateStatus then reads the Info.plist, gets the version from the 155 // -determineUpdateStatus then reads the Info.plist, gets the version from the
153 // CFBundleShortVersionString key, and performs 156 // CFBundleShortVersionString key, and performs
154 // -determineUpdateStatusForVersion: on the main thread. 157 // -determineUpdateStatusForVersion: on the main thread.
155 // -determineUpdateStatusForVersion: does the actual comparison of the version 158 // -determineUpdateStatusForVersion: does the actual comparison of the version
156 // on disk with the running version and calls -updateStatus:version: with the 159 // on disk with the running version and calls -updateStatus:version:error: with
157 // results of its analysis. 160 // the results of its analysis.
158 - (void)determineUpdateStatusAsync; 161 - (void)determineUpdateStatusAsync;
159 - (void)determineUpdateStatus; 162 - (void)determineUpdateStatus;
160 - (void)determineUpdateStatusForVersion:(NSString*)version; 163 - (void)determineUpdateStatusForVersion:(NSString*)version;
161 164
162 // Returns YES if registration_ is definitely on a user ticket. If definitely 165 // Returns YES if registration_ is definitely on a user ticket. If definitely
163 // on a system ticket, or uncertain of ticket type (due to an older version 166 // on a system ticket, or uncertain of ticket type (due to an older version
164 // of Keystone being used), returns NO. 167 // of Keystone being used), returns NO.
165 - (BOOL)isUserTicket; 168 - (BOOL)isUserTicket;
166 169
167 // Returns YES if Keystone is definitely installed at the system level, 170 // Returns YES if Keystone is definitely installed at the system level,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 // tag key. If a full installer (as opposed to a binary diff/delta patch) is 204 // tag key. If a full installer (as opposed to a binary diff/delta patch) is
202 // required, the tag suffix will contain the string "-full". If no special 205 // required, the tag suffix will contain the string "-full". If no special
203 // treatment is required, the tag suffix will be an empty string. 206 // treatment is required, the tag suffix will be an empty string.
204 - (NSString*)tagSuffix; 207 - (NSString*)tagSuffix;
205 208
206 @end // @interface KeystoneGlue (Private) 209 @end // @interface KeystoneGlue (Private)
207 210
208 NSString* const kAutoupdateStatusNotification = @"AutoupdateStatusNotification"; 211 NSString* const kAutoupdateStatusNotification = @"AutoupdateStatusNotification";
209 NSString* const kAutoupdateStatusStatus = @"status"; 212 NSString* const kAutoupdateStatusStatus = @"status";
210 NSString* const kAutoupdateStatusVersion = @"version"; 213 NSString* const kAutoupdateStatusVersion = @"version";
214 NSString* const kAutoupdateStatusErrorMessages = @"errormessages";
211 215
212 namespace { 216 namespace {
213 217
214 NSString* const kChannelKey = @"KSChannelID"; 218 NSString* const kChannelKey = @"KSChannelID";
215 NSString* const kBrandKey = @"KSBrandID"; 219 NSString* const kBrandKey = @"KSBrandID";
216 NSString* const kVersionKey = @"KSVersion"; 220 NSString* const kVersionKey = @"KSVersion";
217 221
218 } // namespace 222 } // namespace
219 223
220 @implementation KeystoneGlue 224 @implementation KeystoneGlue
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 // what's significant here: it's used to locate the outermost part of the 286 // what's significant here: it's used to locate the outermost part of the
283 // application for the existence checker and other operations that need to 287 // application for the existence checker and other operations that need to
284 // see the entire application bundle. 288 // see the entire application bundle.
285 return [base::mac::OuterBundle() infoDictionary]; 289 return [base::mac::OuterBundle() infoDictionary];
286 } 290 }
287 291
288 - (void)loadParameters { 292 - (void)loadParameters {
289 NSBundle* appBundle = base::mac::OuterBundle(); 293 NSBundle* appBundle = base::mac::OuterBundle();
290 NSDictionary* infoDictionary = [self infoDictionary]; 294 NSDictionary* infoDictionary = [self infoDictionary];
291 295
292 NSString* productID = [infoDictionary objectForKey:@"KSProductID"]; 296 NSString* productID = base::mac::ObjCCast<NSString>(
297 [infoDictionary objectForKey:@"KSProductID"]);
293 if (productID == nil) { 298 if (productID == nil) {
294 productID = [appBundle bundleIdentifier]; 299 productID = [appBundle bundleIdentifier];
295 } 300 }
296 301
297 NSString* appPath = [appBundle bundlePath]; 302 NSString* appPath = [appBundle bundlePath];
298 NSString* url = [infoDictionary objectForKey:@"KSUpdateURL"]; 303 NSString* url = base::mac::ObjCCast<NSString>(
299 NSString* version = [infoDictionary objectForKey:kVersionKey]; 304 [infoDictionary objectForKey:@"KSUpdateURL"]);
305 NSString* version = base::mac::ObjCCast<NSString>(
306 [infoDictionary objectForKey:kVersionKey]);
300 307
301 if (!productID || !appPath || !url || !version) { 308 if (!productID || !appPath || !url || !version) {
302 // If parameters required for Keystone are missing, don't use it. 309 // If parameters required for Keystone are missing, don't use it.
303 return; 310 return;
304 } 311 }
305 312
306 NSString* channel = [infoDictionary objectForKey:kChannelKey]; 313 NSString* channel = base::mac::ObjCCast<NSString>(
314 [infoDictionary objectForKey:kChannelKey]);
307 // The stable channel has no tag. If updating to stable, remove the 315 // The stable channel has no tag. If updating to stable, remove the
308 // dev and beta tags since we've been "promoted". 316 // dev and beta tags since we've been "promoted".
309 if (channel == nil) 317 if (channel == nil)
310 channel = ksr::KSRegistrationRemoveExistingTag; 318 channel = ksr::KSRegistrationRemoveExistingTag;
311 319
312 productID_ = [productID retain]; 320 productID_ = [productID retain];
313 appPath_ = [appPath retain]; 321 appPath_ = [appPath retain];
314 url_ = [url retain]; 322 url_ = [url retain];
315 version_ = [version retain]; 323 version_ = [version retain];
316 channel_ = [channel retain]; 324 channel_ = [channel retain];
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 366
359 // Clean up any old user level file. 367 // Clean up any old user level file.
360 if ([fm fileExistsAtPath:userBrandFile]) { 368 if ([fm fileExistsAtPath:userBrandFile]) {
361 [fm removeItemAtPath:userBrandFile error:NULL]; 369 [fm removeItemAtPath:userBrandFile error:NULL];
362 } 370 }
363 371
364 } else { 372 } else {
365 // User 373 // User
366 374
367 NSDictionary* infoDictionary = [self infoDictionary]; 375 NSDictionary* infoDictionary = [self infoDictionary];
368 NSString* appBundleBrandID = [infoDictionary objectForKey:kBrandKey]; 376 NSString* appBundleBrandID = base::mac::ObjCCast<NSString>(
377 [infoDictionary objectForKey:kBrandKey]);
369 378
370 NSString* storedBrandID = nil; 379 NSString* storedBrandID = nil;
371 if ([fm fileExistsAtPath:userBrandFile]) { 380 if ([fm fileExistsAtPath:userBrandFile]) {
372 NSDictionary* storedBrandDict = 381 NSDictionary* storedBrandDict =
373 [NSDictionary dictionaryWithContentsOfFile:userBrandFile]; 382 [NSDictionary dictionaryWithContentsOfFile:userBrandFile];
374 storedBrandID = [storedBrandDict objectForKey:kBrandKey]; 383 storedBrandID = base::mac::ObjCCast<NSString>(
384 [storedBrandDict objectForKey:kBrandKey]);
375 } 385 }
376 386
377 if ((appBundleBrandID != nil) && 387 if ((appBundleBrandID != nil) &&
378 (![storedBrandID isEqualTo:appBundleBrandID])) { 388 (![storedBrandID isEqualTo:appBundleBrandID])) {
379 // App and store don't match, update store and use it. 389 // App and store don't match, update store and use it.
380 NSDictionary* storedBrandDict = 390 NSDictionary* storedBrandDict =
381 [NSDictionary dictionaryWithObject:appBundleBrandID 391 [NSDictionary dictionaryWithObject:appBundleBrandID
382 forKey:kBrandKey]; 392 forKey:kBrandKey];
383 // If Keystone hasn't been installed yet, the location the brand file 393 // If Keystone hasn't been installed yet, the location the brand file
384 // is written to won't exist, so manually create the directory. 394 // is written to won't exist, so manually create the directory.
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 preserveTTToken, ksr::KSRegistrationPreserveTrustedTesterTokenKey, 497 preserveTTToken, ksr::KSRegistrationPreserveTrustedTesterTokenKey,
488 tagValue, ksr::KSRegistrationTagKey, 498 tagValue, ksr::KSRegistrationTagKey,
489 appInfoPlistPath, ksr::KSRegistrationTagPathKey, 499 appInfoPlistPath, ksr::KSRegistrationTagPathKey,
490 tagKey, ksr::KSRegistrationTagKeyKey, 500 tagKey, ksr::KSRegistrationTagKeyKey,
491 brandPath, ksr::KSRegistrationBrandPathKey, 501 brandPath, ksr::KSRegistrationBrandPathKey,
492 brandKey, ksr::KSRegistrationBrandKeyKey, 502 brandKey, ksr::KSRegistrationBrandKeyKey,
493 nil]; 503 nil];
494 } 504 }
495 505
496 - (void)setRegistrationActive { 506 - (void)setRegistrationActive {
497 if (!registration_) 507 DCHECK(registration_);
498 return; 508
499 registrationActive_ = YES; 509 registrationActive_ = YES;
500 510
501 // Should never have zero profiles. Do not report this value. 511 // Should never have zero profiles. Do not report this value.
502 if (!numProfiles_) { 512 if (!numProfiles_) {
503 [registration_ setActive]; 513 [registration_ setActive];
504 return; 514 return;
505 } 515 }
506 516
507 NSError* reportingError = nil; 517 NSError* reportingError = nil;
508 518
(...skipping 20 matching lines...) Expand all
529 NSArray* profileCountsInformation = 539 NSArray* profileCountsInformation =
530 [NSArray arrayWithObjects:numAccountsAttr, numSignedInAccountsAttr, nil]; 540 [NSArray arrayWithObjects:numAccountsAttr, numSignedInAccountsAttr, nil];
531 541
532 if (![registration_ setActiveWithReportingAttributes:profileCountsInformation 542 if (![registration_ setActiveWithReportingAttributes:profileCountsInformation
533 error:&reportingError]) { 543 error:&reportingError]) {
534 VLOG(1) << [reportingError localizedDescription]; 544 VLOG(1) << [reportingError localizedDescription];
535 } 545 }
536 } 546 }
537 547
538 - (void)registerWithKeystone { 548 - (void)registerWithKeystone {
539 [self updateStatus:kAutoupdateRegistering version:nil]; 549 DCHECK(registration_);
550
551 [self updateStatus:kAutoupdateRegistering version:nil error:nil];
540 552
541 NSDictionary* parameters = [self keystoneParameters]; 553 NSDictionary* parameters = [self keystoneParameters];
542 BOOL result = [registration_ registerWithParameters:parameters]; 554 BOOL result = [registration_ registerWithParameters:parameters];
543 if (!result) { 555 if (!result) {
544 [self updateStatus:kAutoupdateRegisterFailed version:nil]; 556 // TODO: If Keystone ever makes a variant of this API with a withError:
557 // parameter, include the error message here in the call to updateStatus:.
558 [self updateStatus:kAutoupdateRegisterFailed version:nil error:nil];
545 return; 559 return;
546 } 560 }
547 561
548 // Upon completion, ksr::KSRegistrationDidCompleteNotification will be 562 // Upon completion, ksr::KSRegistrationDidCompleteNotification will be
549 // posted, and -registrationComplete: will be called. 563 // posted, and -registrationComplete: will be called.
550 564
551 // Set up hourly activity pings. 565 // Set up hourly activity pings.
552 timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour 566 timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour
553 target:self 567 target:self
554 selector:@selector(markActive:) 568 selector:@selector(markActive:)
555 userInfo:nil 569 userInfo:nil
556 repeats:YES]; 570 repeats:YES];
557 } 571 }
558 572
559 - (BOOL)isRegisteredAndActive { 573 - (BOOL)isRegisteredAndActive {
560 return registrationActive_; 574 return registrationActive_;
561 } 575 }
562 576
563 - (void)registrationComplete:(NSNotification*)notification { 577 - (void)registrationComplete:(NSNotification*)notification {
564 NSDictionary* userInfo = [notification userInfo]; 578 NSDictionary* userInfo = [notification userInfo];
565 if ([[userInfo objectForKey:ksr::KSRegistrationStatusKey] boolValue]) { 579 NSNumber* status = base::mac::ObjCCast<NSNumber>(
580 [userInfo objectForKey:ksr::KSRegistrationStatusKey]);
581 NSString* errorMessages = base::mac::ObjCCast<NSString>(
582 [userInfo objectForKey:ksr::KSRegistrationUpdateCheckRawErrorMessagesKey]);
583
584 if ([status boolValue]) {
566 if ([self isSystemTicketDoomed]) { 585 if ([self isSystemTicketDoomed]) {
567 [self updateStatus:kAutoupdateNeedsPromotion version:nil]; 586 [self updateStatus:kAutoupdateNeedsPromotion
587 version:nil
588 error:errorMessages];
568 } else { 589 } else {
569 [self updateStatus:kAutoupdateRegistered version:nil]; 590 [self updateStatus:kAutoupdateRegistered
591 version:nil
592 error:errorMessages];
570 } 593 }
571 } else { 594 } else {
572 // Dump registration_? 595 // Dump registration_?
573 [self updateStatus:kAutoupdateRegisterFailed version:nil]; 596 [self updateStatus:kAutoupdateRegisterFailed
597 version:nil
598 error:errorMessages];
574 } 599 }
575 } 600 }
576 601
577 - (void)stopTimer { 602 - (void)stopTimer {
578 [timer_ invalidate]; 603 [timer_ invalidate];
579 } 604 }
580 605
581 - (void)markActive:(NSTimer*)timer { 606 - (void)markActive:(NSTimer*)timer {
582 [self setRegistrationActive]; 607 [self setRegistrationActive];
583 } 608 }
584 609
585 - (void)checkForUpdate { 610 - (void)checkForUpdate {
586 DCHECK(![self asyncOperationPending]); 611 DCHECK(registration_);
587 612
588 if (!registration_) { 613 if ([self asyncOperationPending]) {
589 [self updateStatus:kAutoupdateCheckFailed version:nil]; 614 // Update check already in process; return without doing anything.
590 return; 615 return;
591 } 616 }
592 617
593 [self updateStatus:kAutoupdateChecking version:nil]; 618 [self updateStatus:kAutoupdateChecking version:nil error:nil];
594 619
595 // All checks from inside Chrome are considered user-initiated, because they 620 // All checks from inside Chrome are considered user-initiated, because they
596 // only happen following a user action, such as visiting the about page. 621 // only happen following a user action, such as visiting the about page.
597 // Non-user-initiated checks are the periodic checks automatically made by 622 // Non-user-initiated checks are the periodic checks automatically made by
598 // Keystone, which don't come through this code path (or even this process). 623 // Keystone, which don't come through this code path (or even this process).
599 [registration_ checkForUpdateWasUserInitiated:YES]; 624 [registration_ checkForUpdateWasUserInitiated:YES];
600 625
601 // Upon completion, ksr::KSRegistrationCheckForUpdateNotification will be 626 // Upon completion, ksr::KSRegistrationCheckForUpdateNotification will be
602 // posted, and -checkForUpdateComplete: will be called. 627 // posted, and -checkForUpdateComplete: will be called.
603 } 628 }
604 629
605 - (void)checkForUpdateComplete:(NSNotification*)notification { 630 - (void)checkForUpdateComplete:(NSNotification*)notification {
606 NSDictionary* userInfo = [notification userInfo]; 631 NSDictionary* userInfo = [notification userInfo];
632 NSNumber* error = base::mac::ObjCCast<NSNumber>(
633 [userInfo objectForKey:ksr::KSRegistrationUpdateCheckErrorKey]);
634 NSNumber* status = base::mac::ObjCCast<NSNumber>(
635 [userInfo objectForKey:ksr::KSRegistrationStatusKey]);
636 NSString* errorMessages = base::mac::ObjCCast<NSString>(
637 [userInfo objectForKey:ksr::KSRegistrationUpdateCheckRawErrorMessagesKey]);
607 638
608 if ([[userInfo objectForKey:ksr::KSRegistrationUpdateCheckErrorKey] 639 if ([error boolValue]) {
609 boolValue]) { 640 [self updateStatus:kAutoupdateCheckFailed
610 [self updateStatus:kAutoupdateCheckFailed version:nil]; 641 version:nil
611 } else if ([[userInfo objectForKey:ksr::KSRegistrationStatusKey] boolValue]) { 642 error:errorMessages];
643 } else if ([status boolValue]) {
612 // If an update is known to be available, go straight to 644 // If an update is known to be available, go straight to
613 // -updateStatus:version:. It doesn't matter what's currently on disk. 645 // -updateStatus:version:. It doesn't matter what's currently on disk.
614 NSString* version = [userInfo objectForKey:ksr::KSRegistrationVersionKey]; 646 NSString* version = base::mac::ObjCCast<NSString>(
615 [self updateStatus:kAutoupdateAvailable version:version]; 647 [userInfo objectForKey:ksr::KSRegistrationVersionKey]);
648 [self updateStatus:kAutoupdateAvailable
649 version:version
650 error:errorMessages];
616 } else { 651 } else {
617 // If no updates are available, check what's on disk, because an update 652 // If no updates are available, check what's on disk, because an update
618 // may have already been installed. This check happens on another thread, 653 // may have already been installed. This check happens on another thread,
619 // and -updateStatus:version: will be called on the main thread when done. 654 // and -updateStatus:version: will be called on the main thread when done.
620 [self determineUpdateStatusAsync]; 655 [self determineUpdateStatusAsync];
621 } 656 }
622 } 657 }
623 658
624 - (void)installUpdate { 659 - (void)installUpdate {
625 DCHECK(![self asyncOperationPending]); 660 DCHECK(registration_);
626 661
627 if (!registration_) { 662 if ([self asyncOperationPending]) {
628 [self updateStatus:kAutoupdateInstallFailed version:nil]; 663 // Update check already in process; return without doing anything.
629 return; 664 return;
630 } 665 }
631 666
632 [self updateStatus:kAutoupdateInstalling version:nil]; 667 [self updateStatus:kAutoupdateInstalling version:nil error:nil];
633 668
634 [registration_ startUpdate]; 669 [registration_ startUpdate];
635 670
636 // Upon completion, ksr::KSRegistrationStartUpdateNotification will be 671 // Upon completion, ksr::KSRegistrationStartUpdateNotification will be
637 // posted, and -installUpdateComplete: will be called. 672 // posted, and -installUpdateComplete: will be called.
638 } 673 }
639 674
640 - (void)installUpdateComplete:(NSNotification*)notification { 675 - (void)installUpdateComplete:(NSNotification*)notification {
641 NSDictionary* userInfo = [notification userInfo]; 676 NSDictionary* userInfo = [notification userInfo];
677 NSNumber* successfulInstall = base::mac::ObjCCast<NSNumber>(
678 [userInfo objectForKey:ksr::KSUpdateCheckSuccessfullyInstalledKey]);
679 NSString* errorMessages = base::mac::ObjCCast<NSString>(
680 [userInfo objectForKey:ksr::KSRegistrationUpdateCheckRawErrorMessagesKey]);
642 681
643 // http://crbug.com/160308 and b/7517358: when using system Keystone and on 682 // http://crbug.com/160308 and b/7517358: when using system Keystone and on
644 // a user ticket, KSUpdateCheckSuccessfulKey will be NO even when an update 683 // a user ticket, KSUpdateCheckSuccessfulKey will be NO even when an update
645 // was installed correctly, so don't check it. It should be redudnant when 684 // was installed correctly, so don't check it. It should be redudnant when
646 // KSUpdateCheckSuccessfullyInstalledKey is checked. 685 // KSUpdateCheckSuccessfullyInstalledKey is checked.
647 if (![[userInfo objectForKey:ksr::KSUpdateCheckSuccessfullyInstalledKey] 686 if (![successfulInstall intValue]) {
648 intValue]) { 687 [self updateStatus:kAutoupdateInstallFailed
649 [self updateStatus:kAutoupdateInstallFailed version:nil]; 688 version:nil
689 error:errorMessages];
650 } else { 690 } else {
651 updateSuccessfullyInstalled_ = YES; 691 updateSuccessfullyInstalled_ = YES;
652 692
653 // Nothing in the notification dictionary reports the version that was 693 // Nothing in the notification dictionary reports the version that was
654 // installed. Figure it out based on what's on disk. 694 // installed. Figure it out based on what's on disk.
655 [self determineUpdateStatusAsync]; 695 [self determineUpdateStatusAsync];
656 } 696 }
657 } 697 }
658 698
659 - (NSString*)currentlyInstalledVersion { 699 - (NSString*)currentlyInstalledVersion {
660 NSString* appInfoPlistPath = [self appInfoPlistPath]; 700 NSString* appInfoPlistPath = [self appInfoPlistPath];
661 NSDictionary* infoPlist = 701 NSDictionary* infoPlist =
662 [NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath]; 702 [NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath];
663 return [infoPlist objectForKey:@"CFBundleShortVersionString"]; 703 return base::mac::ObjCCast<NSString>(
704 [infoPlist objectForKey:@"CFBundleShortVersionString"]);
664 } 705 }
665 706
666 // Runs on the main thread. 707 // Runs on the main thread.
667 - (void)determineUpdateStatusAsync { 708 - (void)determineUpdateStatusAsync {
668 DCHECK([NSThread isMainThread]); 709 DCHECK([NSThread isMainThread]);
669 710
670 PerformBridge::PostPerform(self, @selector(determineUpdateStatus)); 711 PerformBridge::PostPerform(self, @selector(determineUpdateStatus));
671 } 712 }
672 713
673 // Runs on a thread managed by WorkerPool. 714 // Runs on a thread managed by WorkerPool.
(...skipping 28 matching lines...) Expand all
702 status = kAutoupdateCurrent; 743 status = kAutoupdateCurrent;
703 } else { 744 } else {
704 // If the version on disk doesn't match what's currently running, an 745 // If the version on disk doesn't match what's currently running, an
705 // update must have been applied in the background, without this app's 746 // update must have been applied in the background, without this app's
706 // direct participation. Leave updateSuccessfullyInstalled_ alone 747 // direct participation. Leave updateSuccessfullyInstalled_ alone
707 // because there's no direct knowledge of what actually happened. 748 // because there's no direct knowledge of what actually happened.
708 status = kAutoupdateInstalled; 749 status = kAutoupdateInstalled;
709 } 750 }
710 } 751 }
711 752
712 [self updateStatus:status version:version]; 753 [self updateStatus:status version:version error:nil];
713 } 754 }
714 755
715 - (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version { 756 - (void)updateStatus:(AutoupdateStatus)status
757 version:(NSString*)version
758 error:(NSString*)error {
716 NSNumber* statusNumber = [NSNumber numberWithInt:status]; 759 NSNumber* statusNumber = [NSNumber numberWithInt:status];
717 NSMutableDictionary* dictionary = 760 NSMutableDictionary* dictionary =
718 [NSMutableDictionary dictionaryWithObject:statusNumber 761 [NSMutableDictionary dictionaryWithObject:statusNumber
719 forKey:kAutoupdateStatusStatus]; 762 forKey:kAutoupdateStatusStatus];
720 if (version) { 763 if (version) {
721 [dictionary setObject:version forKey:kAutoupdateStatusVersion]; 764 [dictionary setObject:version forKey:kAutoupdateStatusVersion];
722 } 765 }
766 if (error) {
767 [dictionary setObject:version forKey:kAutoupdateStatusErrorMessages];
768 }
723 769
724 NSNotification* notification = 770 NSNotification* notification =
725 [NSNotification notificationWithName:kAutoupdateStatusNotification 771 [NSNotification notificationWithName:kAutoupdateStatusNotification
726 object:self 772 object:self
727 userInfo:dictionary]; 773 userInfo:dictionary];
728 recentNotification_.reset([notification retain]); 774 recentNotification_.reset([notification retain]);
729 775
730 [[NSNotificationCenter defaultCenter] postNotification:notification]; 776 [[NSNotificationCenter defaultCenter] postNotification:notification];
731 } 777 }
732 778
733 - (NSNotification*)recentNotification { 779 - (NSNotification*)recentNotification {
734 return [[recentNotification_ retain] autorelease]; 780 return [[recentNotification_ retain] autorelease];
735 } 781 }
736 782
737 - (AutoupdateStatus)recentStatus { 783 - (AutoupdateStatus)recentStatus {
738 NSDictionary* dictionary = [recentNotification_ userInfo]; 784 NSDictionary* dictionary = [recentNotification_ userInfo];
739 return static_cast<AutoupdateStatus>( 785 NSNumber* status = base::mac::ObjCCastStrict<NSNumber>(
740 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); 786 [dictionary objectForKey:kAutoupdateStatusStatus]);
787 return static_cast<AutoupdateStatus>([status intValue]);
741 } 788 }
742 789
743 - (BOOL)asyncOperationPending { 790 - (BOOL)asyncOperationPending {
744 AutoupdateStatus status = [self recentStatus]; 791 AutoupdateStatus status = [self recentStatus];
745 return status == kAutoupdateRegistering || 792 return status == kAutoupdateRegistering ||
746 status == kAutoupdateChecking || 793 status == kAutoupdateChecking ||
747 status == kAutoupdateInstalling || 794 status == kAutoupdateInstalling ||
748 status == kAutoupdatePromoting; 795 status == kAutoupdatePromoting;
749 } 796 }
750 797
751 - (BOOL)isUserTicket { 798 - (BOOL)isUserTicket {
799 DCHECK(registration_);
752 return [registration_ ticketType] == ksr::kKSRegistrationUserTicket; 800 return [registration_ ticketType] == ksr::kKSRegistrationUserTicket;
753 } 801 }
754 802
755 - (BOOL)isSystemKeystone { 803 - (BOOL)isSystemKeystone {
756 struct stat statbuf; 804 struct stat statbuf;
757 if (stat("/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/" 805 if (stat("/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/"
758 "Contents/MacOS/ksadmin", 806 "Contents/MacOS/ksadmin",
759 &statbuf) != 0) { 807 &statbuf) != 0) {
760 return NO; 808 return NO;
761 } 809 }
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 base::mac::NSToCFCast(prompt))); 897 base::mac::NSToCFCast(prompt)));
850 if (!authorization.get()) { 898 if (!authorization.get()) {
851 return; 899 return;
852 } 900 }
853 901
854 [self promoteTicketWithAuthorization:authorization.release() synchronous:NO]; 902 [self promoteTicketWithAuthorization:authorization.release() synchronous:NO];
855 } 903 }
856 904
857 - (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg 905 - (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg
858 synchronous:(BOOL)synchronous { 906 synchronous:(BOOL)synchronous {
907 DCHECK(registration_);
908
859 base::mac::ScopedAuthorizationRef authorization(authorization_arg); 909 base::mac::ScopedAuthorizationRef authorization(authorization_arg);
860 authorization_arg = NULL; 910 authorization_arg = NULL;
861 911
862 if ([self asyncOperationPending]) { 912 if ([self asyncOperationPending]) {
863 // Starting a synchronous operation while an asynchronous one is pending 913 // Starting a synchronous operation while an asynchronous one is pending
864 // could be trouble. 914 // could be trouble.
865 return; 915 return;
866 } 916 }
867 if (!synchronous && ![self wantsPromotion]) { 917 if (!synchronous && ![self wantsPromotion]) {
868 // If operating synchronously, the call came from the installer, which 918 // If operating synchronously, the call came from the installer, which
869 // means that a system ticket is required. Otherwise, only allow 919 // means that a system ticket is required. Otherwise, only allow
870 // promotion if it's wanted. 920 // promotion if it's wanted.
871 return; 921 return;
872 } 922 }
873 923
874 synchronousPromotion_ = synchronous; 924 synchronousPromotion_ = synchronous;
875 925
876 [self updateStatus:kAutoupdatePromoting version:nil]; 926 [self updateStatus:kAutoupdatePromoting version:nil error:nil];
877 927
878 // TODO(mark): Remove when able! 928 // TODO(mark): Remove when able!
879 // 929 //
880 // keystone_promote_preflight will copy the current brand information out to 930 // keystone_promote_preflight will copy the current brand information out to
881 // the system level so all users can share the data as part of the ticket 931 // the system level so all users can share the data as part of the ticket
882 // promotion. 932 // promotion.
883 // 933 //
884 // It will also ensure that the Keystone system ticket store is in a usable 934 // It will also ensure that the Keystone system ticket store is in a usable
885 // state for all users on the system. Ideally, Keystone's installer or 935 // state for all users on the system. Ideally, Keystone's installer or
886 // another part of Keystone would handle this. The underlying problem is 936 // another part of Keystone would handle this. The underlying problem is
(...skipping 26 matching lines...) Expand all
913 963
914 int exit_status; 964 int exit_status;
915 OSStatus status = base::mac::ExecuteWithPrivilegesAndWait( 965 OSStatus status = base::mac::ExecuteWithPrivilegesAndWait(
916 authorization, 966 authorization,
917 preflightPathC, 967 preflightPathC,
918 kAuthorizationFlagDefaults, 968 kAuthorizationFlagDefaults,
919 arguments, 969 arguments,
920 NULL, // pipe 970 NULL, // pipe
921 &exit_status); 971 &exit_status);
922 if (status != errAuthorizationSuccess) { 972 if (status != errAuthorizationSuccess) {
923 OSSTATUS_LOG(ERROR, status) 973 // It's possible to get an OS-provided error string for this return code
924 << "AuthorizationExecuteWithPrivileges preflight"; 974 // using base::mac::DescriptionFromOSStatus, but most of those strings are
925 [self updateStatus:kAutoupdatePromoteFailed version:nil]; 975 // not useful/actionable for users, so we stick with the error code instead.
976 NSString* errorMessage =
977 l10n_util::GetNSStringFWithFixup(IDS_PROMOTE_PREFLIGHT_LAUNCH_ERROR,
978 base::IntToString16(status));
979 [self updateStatus:kAutoupdatePromoteFailed
980 version:nil
981 error:errorMessage];
926 return; 982 return;
927 } 983 }
928 if (exit_status != 0) { 984 if (exit_status != 0) {
929 LOG(ERROR) << "keystone_promote_preflight status " << exit_status; 985 NSString* errorMessage =
930 [self updateStatus:kAutoupdatePromoteFailed version:nil]; 986 l10n_util::GetNSStringFWithFixup(IDS_PROMOTE_PREFLIGHT_SCRIPT_ERROR,
987 base::IntToString16(status));
988 [self updateStatus:kAutoupdatePromoteFailed
989 version:nil
990 error:errorMessage];
931 return; 991 return;
932 } 992 }
933 993
934 // Hang on to the AuthorizationRef so that it can be used once promotion is 994 // Hang on to the AuthorizationRef so that it can be used once promotion is
935 // complete. Do this before asking Keystone to promote the ticket, because 995 // complete. Do this before asking Keystone to promote the ticket, because
936 // -promotionComplete: may be called from inside the Keystone promotion 996 // -promotionComplete: may be called from inside the Keystone promotion
937 // call. 997 // call.
938 authorization_.swap(authorization); 998 authorization_.swap(authorization);
939 999
940 NSDictionary* parameters = [self keystoneParameters]; 1000 NSDictionary* parameters = [self keystoneParameters];
941 1001
942 // If the brand file is user level, update parameters to point to the new 1002 // If the brand file is user level, update parameters to point to the new
943 // system level file during promotion. 1003 // system level file during promotion.
944 if (brandFileType_ == kBrandFileTypeUser) { 1004 if (brandFileType_ == kBrandFileTypeUser) {
945 NSMutableDictionary* temp_parameters = 1005 NSMutableDictionary* temp_parameters =
946 [[parameters mutableCopy] autorelease]; 1006 [[parameters mutableCopy] autorelease];
947 [temp_parameters setObject:SystemBrandFilePath() 1007 [temp_parameters setObject:SystemBrandFilePath()
948 forKey:ksr::KSRegistrationBrandPathKey]; 1008 forKey:ksr::KSRegistrationBrandPathKey];
949 parameters = temp_parameters; 1009 parameters = temp_parameters;
950 } 1010 }
951 1011
952 if (![registration_ promoteWithParameters:parameters 1012 if (![registration_ promoteWithParameters:parameters
953 authorization:authorization_]) { 1013 authorization:authorization_]) {
954 [self updateStatus:kAutoupdatePromoteFailed version:nil]; 1014 // TODO: If Keystone ever makes a variant of this API with a withError:
1015 // parameter, include the error message here in the call to updateStatus:.
1016 [self updateStatus:kAutoupdatePromoteFailed version:nil error:nil];
955 authorization_.reset(); 1017 authorization_.reset();
956 return; 1018 return;
957 } 1019 }
958 1020
959 // Upon completion, ksr::KSRegistrationPromotionDidCompleteNotification will 1021 // Upon completion, ksr::KSRegistrationPromotionDidCompleteNotification will
960 // be posted, and -promotionComplete: will be called. 1022 // be posted, and -promotionComplete: will be called.
961 1023
962 // If synchronous, see to it that this happens immediately. Give it a 1024 // If synchronous, see to it that this happens immediately. Give it a
963 // 10-second deadline. 1025 // 10-second deadline.
964 if (synchronous) { 1026 if (synchronous) {
965 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false); 1027 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
966 } 1028 }
967 } 1029 }
968 1030
969 - (void)promotionComplete:(NSNotification*)notification { 1031 - (void)promotionComplete:(NSNotification*)notification {
970 NSDictionary* userInfo = [notification userInfo]; 1032 NSDictionary* userInfo = [notification userInfo];
971 if ([[userInfo objectForKey:ksr::KSRegistrationStatusKey] boolValue]) { 1033 NSNumber* status = base::mac::ObjCCast<NSNumber>(
1034 [userInfo objectForKey:ksr::KSRegistrationStatusKey]);
1035
1036 if ([status boolValue]) {
972 if (synchronousPromotion_) { 1037 if (synchronousPromotion_) {
973 // Short-circuit: if performing a synchronous promotion, the promotion 1038 // Short-circuit: if performing a synchronous promotion, the promotion
974 // came from the installer, which already set the permissions properly. 1039 // came from the installer, which already set the permissions properly.
975 // Rather than run a duplicate permission-changing operation, jump 1040 // Rather than run a duplicate permission-changing operation, jump
976 // straight to "done." 1041 // straight to "done."
977 [self changePermissionsForPromotionComplete]; 1042 [self changePermissionsForPromotionComplete];
978 } else { 1043 } else {
979 [self changePermissionsForPromotionAsync]; 1044 [self changePermissionsForPromotionAsync];
980 } 1045 }
981 } else { 1046 } else {
982 authorization_.reset(); 1047 authorization_.reset();
983 [self updateStatus:kAutoupdatePromoteFailed version:nil]; 1048 [self updateStatus:kAutoupdatePromoteFailed version:nil error:nil];
984 } 1049 }
985 1050
986 if (synchronousPromotion_) { 1051 if (synchronousPromotion_) {
987 // The run loop doesn't need to wait for this any longer. 1052 // The run loop doesn't need to wait for this any longer.
988 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); 1053 CFRunLoopRef runLoop = CFRunLoopGetCurrent();
989 CFRunLoopStop(runLoop); 1054 CFRunLoopStop(runLoop);
990 CFRunLoopWakeUp(runLoop); 1055 CFRunLoopWakeUp(runLoop);
991 } 1056 }
992 } 1057 }
993 1058
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 1094
1030 SEL selector = @selector(changePermissionsForPromotionComplete); 1095 SEL selector = @selector(changePermissionsForPromotionComplete);
1031 [self performSelectorOnMainThread:selector 1096 [self performSelectorOnMainThread:selector
1032 withObject:nil 1097 withObject:nil
1033 waitUntilDone:NO]; 1098 waitUntilDone:NO];
1034 } 1099 }
1035 1100
1036 - (void)changePermissionsForPromotionComplete { 1101 - (void)changePermissionsForPromotionComplete {
1037 authorization_.reset(); 1102 authorization_.reset();
1038 1103
1039 [self updateStatus:kAutoupdatePromoted version:nil]; 1104 [self updateStatus:kAutoupdatePromoted version:nil error:nil];
1040 } 1105 }
1041 1106
1042 - (void)setAppPath:(NSString*)appPath { 1107 - (void)setAppPath:(NSString*)appPath {
1043 if (appPath != appPath_) { 1108 if (appPath != appPath_) {
1044 [appPath_ release]; 1109 [appPath_ release];
1045 appPath_ = [appPath copy]; 1110 appPath_ = [appPath copy];
1046 } 1111 }
1047 } 1112 }
1048 1113
1049 - (BOOL)wantsFullInstaller { 1114 - (BOOL)wantsFullInstaller {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1131 return [KeystoneGlue defaultKeystoneGlue] != nil; 1196 return [KeystoneGlue defaultKeystoneGlue] != nil;
1132 } 1197 }
1133 1198
1134 base::string16 CurrentlyInstalledVersion() { 1199 base::string16 CurrentlyInstalledVersion() {
1135 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; 1200 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
1136 NSString* version = [keystoneGlue currentlyInstalledVersion]; 1201 NSString* version = [keystoneGlue currentlyInstalledVersion];
1137 return base::SysNSStringToUTF16(version); 1202 return base::SysNSStringToUTF16(version);
1138 } 1203 }
1139 1204
1140 } // namespace keystone_glue 1205 } // namespace keystone_glue
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698