summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-19 02:18:22 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-19 02:18:22 +0000
commit9622800ab359b3b110a85bb9a420710f8745e122 (patch)
tree942322967a38fe1c9ee1103416517d9e0345ee29
parentc27bd19ebde897a50d5a08dcce0fbe1280bcc5ba (diff)
downloadchromium_src-9622800ab359b3b110a85bb9a420710f8745e122.zip
chromium_src-9622800ab359b3b110a85bb9a420710f8745e122.tar.gz
chromium_src-9622800ab359b3b110a85bb9a420710f8745e122.tar.bz2
Merge trunk r35030 to the 249 branch.
Adapt Chrome to use KeystoneRegistration 1.0.7.1306. Use "tag path" and "tag key" to direct Keystone to use a tag stored in the application as opposed to in its ticket. BUG=30730 TEST= - ksadmin --print-ticket --productid com.google.Chrome should show tagPath pointing to GC.app/Contents/Info.plist, and tagKey of KSChannelID; - ksadmin --print-tag --productid com.google.Chrome should show the value of the KSChannelID key in GC.app/Contents/Info.plist; this should be the tag that is used for autoupdates The above steps should be validated after the following operations: - launching Chrome when on a user ticket, - promoting Chrome from a user ticket to a system ticket, and - when a Chrome update is applied (using this version of keystone_install.sh) when on either a user or a system ticket. The tagPath and tagKey will NOT be set when launching Chrome on a system (promoted) ticket, but they WILL be set when the ticket is initially promoted and also when an update is applied using this version of keystone_install.sh. Review URL: http://codereview.chromium.org/506061 TBR=mark@chromium.org Review URL: http://codereview.chromium.org/505055 git-svn-id: svn://svn.chromium.org/chrome/branches/249/src@35031 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/cocoa/keystone_glue.mm94
-rwxr-xr-xchrome/chrome.gyp10
-rwxr-xr-xchrome/tools/build/mac/keystone_install.sh100
-rwxr-xr-xchrome/tools/build/mac/keystone_install_test.sh11
4 files changed, 171 insertions, 44 deletions
diff --git a/chrome/browser/cocoa/keystone_glue.mm b/chrome/browser/cocoa/keystone_glue.mm
index 3ef10bc..468eca90 100644
--- a/chrome/browser/cocoa/keystone_glue.mm
+++ b/chrome/browser/cocoa/keystone_glue.mm
@@ -32,6 +32,15 @@ typedef enum {
kKSRegistrationDontKnowWhatKindOfTicket,
} KSRegistrationTicketType;
+NSString* KSRegistrationVersionKey = @"Version";
+NSString* KSRegistrationExistenceCheckerTypeKey = @"ExistenceCheckerType";
+NSString* KSRegistrationExistenceCheckerStringKey = @"ExistenceCheckerString";
+NSString* KSRegistrationServerURLStringKey = @"URLString";
+NSString* KSRegistrationPreserveTrustedTesterTokenKey = @"PreserveTTT";
+NSString* KSRegistrationTagKey = @"Tag";
+NSString* KSRegistrationTagPathKey = @"TagPath";
+NSString* KSRegistrationTagKeyKey = @"TagKey";
+
NSString *KSRegistrationDidCompleteNotification =
@"KSRegistrationDidCompleteNotification";
NSString *KSRegistrationPromotionDidCompleteNotification =
@@ -40,7 +49,6 @@ NSString *KSRegistrationPromotionDidCompleteNotification =
NSString *KSRegistrationCheckForUpdateNotification =
@"KSRegistrationCheckForUpdateNotification";
NSString *KSRegistrationStatusKey = @"Status";
-NSString *KSRegistrationVersionKey = @"Version";
NSString *KSRegistrationUpdateCheckErrorKey = @"Error";
NSString *KSRegistrationStartUpdateNotification =
@@ -57,20 +65,10 @@ NSString *KSRegistrationRemoveExistingTag = @"";
+ (id)registrationWithProductID:(NSString*)productID;
-- (BOOL)registerWithVersion:(NSString*)version
- existenceCheckerType:(KSExistenceCheckerType)xctype
- existenceCheckerString:(NSString*)xc
- serverURLString:(NSString*)serverURLString
- preserveTTToken:(BOOL)preserveToken
- tag:(NSString*)tag;
-
-- (BOOL)promoteWithVersion:(NSString*)version
- existenceCheckerType:(KSExistenceCheckerType)xctype
- existenceCheckerString:(NSString*)xc
- serverURLString:(NSString*)serverURLString
- preserveTTToken:(BOOL)preserveToken
- tag:(NSString*)tag
- authorization:(AuthorizationRef)authorization;
+- (BOOL)registerWithParameters:(NSDictionary*)args;
+
+- (BOOL)promoteWithParameters:(NSDictionary*)args
+ authorization:(AuthorizationRef)authorization;
- (void)setActive;
- (void)checkForUpdate;
@@ -81,6 +79,14 @@ NSString *KSRegistrationRemoveExistingTag = @"";
@interface KeystoneGlue(Private)
+// Returns the path to the application's Info.plist file. This returns the
+// outer application bundle's Info.plist, not the framework's Info.plist.
+- (NSString*)appInfoPlistPath;
+
+// Returns a dictionary containing parameters to be used for a KSRegistration
+// -registerWithParameters: or -promoteWithParameters:authorization: call.
+- (NSDictionary*)keystoneParameters;
+
// Called when Keystone registration completes.
- (void)registrationComplete:(NSNotification*)notification;
@@ -145,6 +151,12 @@ const NSString* const kAutoupdateStatusNotification =
const NSString* const kAutoupdateStatusStatus = @"status";
const NSString* const kAutoupdateStatusVersion = @"version";
+namespace {
+
+const NSString* const kChannelKey = @"KSChannelID";
+
+} // namespace
+
@implementation KeystoneGlue
+ (id)defaultKeystoneGlue {
@@ -233,7 +245,7 @@ const NSString* const kAutoupdateStatusVersion = @"version";
return;
}
- NSString* channel = [infoDictionary objectForKey:@"KSChannelID"];
+ NSString* channel = [infoDictionary objectForKey:kChannelKey];
// The stable channel has no tag. If updating to stable, remove the
// dev and beta tags since we've been "promoted".
if (channel == nil)
@@ -268,15 +280,35 @@ const NSString* const kAutoupdateStatusVersion = @"version";
return YES;
}
+- (NSString*)appInfoPlistPath {
+ // NSBundle ought to have a way to access this path directly, but it
+ // doesn't.
+ return [[appPath_ stringByAppendingPathComponent:@"Contents"]
+ stringByAppendingPathComponent:@"Info.plist"];
+}
+
+- (NSDictionary*)keystoneParameters {
+ NSNumber* xcType = [NSNumber numberWithInt:kKSPathExistenceChecker];
+ NSNumber* preserveTTToken = [NSNumber numberWithBool:YES];
+ NSString* tagPath = [self appInfoPlistPath];
+
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ version_, KSRegistrationVersionKey,
+ xcType, KSRegistrationExistenceCheckerTypeKey,
+ appPath_, KSRegistrationExistenceCheckerStringKey,
+ url_, KSRegistrationServerURLStringKey,
+ preserveTTToken, KSRegistrationPreserveTrustedTesterTokenKey,
+ channel_, KSRegistrationTagKey,
+ tagPath, KSRegistrationTagPathKey,
+ kChannelKey, KSRegistrationTagKeyKey,
+ nil];
+}
+
- (void)registerWithKeystone {
[self updateStatus:kAutoupdateRegistering version:nil];
- if (![registration_ registerWithVersion:version_
- existenceCheckerType:kKSPathExistenceChecker
- existenceCheckerString:appPath_
- serverURLString:url_
- preserveTTToken:YES
- tag:channel_]) {
+ NSDictionary* parameters = [self keystoneParameters];
+ if (![registration_ registerWithParameters:parameters]) {
[self updateStatus:kAutoupdateRegisterFailed version:nil];
return;
}
@@ -398,9 +430,7 @@ const NSString* const kAutoupdateStatusVersion = @"version";
- (void)determineUpdateStatus {
DCHECK(![NSThread isMainThread]);
- NSString* appInfoPlistPath =
- [[appPath_ stringByAppendingPathComponent:@"Contents"]
- stringByAppendingPathComponent:@"Info.plist"];
+ NSString* appInfoPlistPath = [self appInfoPlistPath];
NSDictionary* infoPlist =
[NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath];
NSString* version = [infoPlist objectForKey:@"CFBundleShortVersionString"];
@@ -609,8 +639,8 @@ const NSString* const kAutoupdateStatusVersion = @"version";
// causes http://b/2289908, which this workaround addresses.
//
// This is run synchronously, which isn't optimal, but
- // -[KSRegistration promoteWithVersion:...] is currently synchronous too,
- // and this operation needs to happen before that one.
+ // -[KSRegistration promoteWithParameters:authorization:] is currently
+ // synchronous too, and this operation needs to happen before that one.
//
// TODO(mark): Make asynchronous. That only makes sense if the promotion
// operation itself is asynchronous too. http://b/2290009. Hopefully,
@@ -647,13 +677,9 @@ const NSString* const kAutoupdateStatusVersion = @"version";
// call.
authorization_.swap(authorization);
- if (![registration_ promoteWithVersion:version_
- existenceCheckerType:kKSPathExistenceChecker
- existenceCheckerString:appPath_
- serverURLString:url_
- preserveTTToken:YES
- tag:channel_
- authorization:authorization_]) {
+ NSDictionary* parameters = [self keystoneParameters];
+ if (![registration_ promoteWithParameters:parameters
+ authorization:authorization_]) {
[self updateStatus:kAutoupdatePromoteFailed version:nil];
authorization_.reset();
return;
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 440b610..a7a0e13 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3827,13 +3827,15 @@
{
# Modify the Info.plist as needed. The script explains why this
# is needed. This is also done in the helper_app and chrome_dll
- # targets. Use -b0 and -k0 to not include any Breakpad or
- # Keystone information; that all goes into the framework's
- # Info.plist. Use -s1 to include Subversion information.
+ # targets. Use -b0 to not include any Breakpad information; that
+ # all goes into the framework's Info.plist. Keystone information
+ # is included if Keystone is enabled because the ticket will
+ # reference this Info.plist to determine the tag of the installed
+ # product. Use -s1 to include Subversion information.
'postbuild_name': 'Tweak Info.plist',
'action': ['<(tweak_info_plist_path)',
'-b0',
- '-k0',
+ '-k<(mac_keystone)',
'-s1',
'<(branding)',
'<(mac_bundle_id)'],
diff --git a/chrome/tools/build/mac/keystone_install.sh b/chrome/tools/build/mac/keystone_install.sh
index e4fd4cb..67e3a78 100755
--- a/chrome/tools/build/mac/keystone_install.sh
+++ b/chrome/tools/build/mac/keystone_install.sh
@@ -123,6 +123,79 @@ function ensure_writable_symlink() {
return 0
}
+# Prints the version of ksadmin, as reported by ksadmin --ksadmin-version, to
+# stdout. This function operates with "static" variables: it will only check
+# the ksadmin version once per script run. If ksadmin is old enough to not
+# support --ksadmin-version, or another error occurs, this function prints an
+# empty string.
+G_CHECKED_KSADMIN_VERSION=
+G_KSADMIN_VERSION=
+function ksadmin_version() {
+ if [ -z "${G_CHECKED_KSADMIN_VERSION}" ] ; then
+ G_CHECKED_KSADMIN_VERSION=1
+ G_KSADMIN_VERSION=$(ksadmin --ksadmin-version || true)
+ fi
+ echo "${G_KSADMIN_VERSION}"
+ return 0
+}
+
+# Compares the installed ksadmin version against a supplied version number,
+# and returns 0 (true) if the number to check is the same as or newer than the
+# installed Keystone. Returns 1 (false) if the installed Keystone version
+# number cannot be determined or if the number to check is less than the
+# installed Keystone. The check argument should be a string of the form
+# "major.minor.micro.build".
+function is_ksadmin_version_ge() {
+ CHECK_VERSION=${1}
+ KSADMIN_VERSION=$(ksadmin_version)
+ if [ -n "${KSADMIN_VERSION}" ] ; then
+ VER_RE='^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$'
+
+ KSADMIN_VERSION_MAJOR=$(sed -Ene "s/${VER_RE}/\1/p" <<< ${KSADMIN_VERSION})
+ KSADMIN_VERSION_MINOR=$(sed -Ene "s/${VER_RE}/\2/p" <<< ${KSADMIN_VERSION})
+ KSADMIN_VERSION_MICRO=$(sed -Ene "s/${VER_RE}/\3/p" <<< ${KSADMIN_VERSION})
+ KSADMIN_VERSION_BUILD=$(sed -Ene "s/${VER_RE}/\4/p" <<< ${KSADMIN_VERSION})
+
+ CHECK_VERSION_MAJOR=$(sed -Ene "s/${VER_RE}/\1/p" <<< ${CHECK_VERSION})
+ CHECK_VERSION_MINOR=$(sed -Ene "s/${VER_RE}/\2/p" <<< ${CHECK_VERSION})
+ CHECK_VERSION_MICRO=$(sed -Ene "s/${VER_RE}/\3/p" <<< ${CHECK_VERSION})
+ CHECK_VERSION_BUILD=$(sed -Ene "s/${VER_RE}/\4/p" <<< ${CHECK_VERSION})
+
+ if [ ${KSADMIN_VERSION_MAJOR} -gt ${CHECK_VERSION_MAJOR} ] ||
+ ([ ${KSADMIN_VERSION_MAJOR} -eq ${CHECK_VERSION_MAJOR} ] && (
+ [ ${KSADMIN_VERSION_MINOR} -gt ${CHECK_VERSION_MINOR} ] ||
+ ([ ${KSADMIN_VERSION_MINOR} -eq ${CHECK_VERSION_MINOR} ] && (
+ [ ${KSADMIN_VERSION_MICRO} -gt ${CHECK_VERSION_MICRO} ] ||
+ ([ ${KSADMIN_VERSION_MICRO} -eq ${CHECK_VERSION_MICRO} ] &&
+ [ ${KSADMIN_VERSION_BUILD} -ge ${CHECK_VERSION_BUILD} ])
+ ))
+ )) ; then
+ return 0
+ fi
+ fi
+
+ return 1
+}
+
+# Returns 0 (true) if ksadmin supports --tag.
+function ksadmin_supports_tag() {
+ KSADMIN_VERSION=$(ksadmin_version)
+ if [ -n "${KSADMIN_VERSION}" ] ; then
+ # A ksadmin that recognizes --ksadmin-version and provides a version
+ # number is new enough to recognize --tag.
+ return 0
+ fi
+ return 1
+}
+
+# Returns 0 (true) if ksadmin supports --tag-path and --tag-key.
+function ksadmin_supports_tagpath_tagkey() {
+ # --tag-path and --tag-key were introduced in Keystone 1.0.7.1306.
+ is_ksadmin_version_ge 1.0.7.1306
+ # The return value of is_ksadmin_version_ge is used as this function's
+ # return value.
+}
+
# The argument should be the disk image path. Make sure it exists.
if [ $# -lt 1 ] || [ ! -d "${1}" ]; then
exit 2
@@ -325,7 +398,9 @@ NEW_VERSION_KS=$(defaults read "${NEW_KS_PLIST}" "${KS_VERSION_KEY}" || exit 9)
URL=$(defaults read "${NEW_KS_PLIST}" KSUpdateURL || exit 9)
# The channel ID is optional. Suppress stderr to prevent Keystone from seeing
# possible error output.
-CHANNEL_ID=$(defaults read "${NEW_KS_PLIST}" KSChannelID 2>/dev/null || true)
+CHANNEL_ID_KEY=KSChannelID
+CHANNEL_ID=$(defaults read "${NEW_KS_PLIST}" "${CHANNEL_ID_KEY}" 2>/dev/null ||
+ true)
# Make sure that the update was successful by comparing the version found in
# the update with the version now on disk.
@@ -337,10 +412,25 @@ fi
# lsregister's exit codes shouldn't be confused with this script's own.
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister "${DEST}" || true
+# Call ksadmin_version once to prime the global state. This is needed because
+# subsequent calls to ksadmin_version that occur in $(...) expansions will not
+# affect the global state (although they can read from the already-initialized
+# global state) and thus will cause a new ksadmin --ksadmin-version process to
+# run for each check unless the globals have been properly initialized
+# beforehand.
+ksadmin_version >& /dev/null || true
+
# Notify Keystone.
-KSADMIN_VERSION=$(ksadmin --ksadmin-version || true)
-if [ -n "${KSADMIN_VERSION}" ] ; then
- # If ksadmin recognizes --ksadmin-version, it will recognize --tag.
+if ksadmin_supports_tagpath_tagkey ; then
+ ksadmin --register \
+ -P "${PRODUCT_ID}" \
+ --version "${NEW_VERSION_KS}" \
+ --xcpath "${DEST}" \
+ --url "${URL}" \
+ --tag "${CHANNEL_ID}" \
+ --tag-path "${DEST}/Contents/Info.plist" \
+ --tag-key "${CHANNEL_ID_KEY}" || exit 11
+elif ksadmin_supports_tag ; then
ksadmin --register \
-P "${PRODUCT_ID}" \
--version "${NEW_VERSION_KS}" \
@@ -348,8 +438,6 @@ if [ -n "${KSADMIN_VERSION}" ] ; then
--url "${URL}" \
--tag "${CHANNEL_ID}" || exit 11
else
- # Older versions of ksadmin don't recognize --tag. The application will
- # set the tag when it runs.
ksadmin --register \
-P "${PRODUCT_ID}" \
--version "${NEW_VERSION_KS}" \
diff --git a/chrome/tools/build/mac/keystone_install_test.sh b/chrome/tools/build/mac/keystone_install_test.sh
index 3b69de7..32930bf 100755
--- a/chrome/tools/build/mac/keystone_install_test.sh
+++ b/chrome/tools/build/mac/keystone_install_test.sh
@@ -22,6 +22,9 @@ PRODNAME="Google Chrome"
APPNAME="${PRODNAME}.app"
FWKNAME="${PRODNAME} Framework.framework"
+# The version number for fake ksadmin to pretend to be
+KSADMIN_VERSION_LIE="1.0.7.1306"
+
# Temp directory to be used as the disk image (source)
TEMPDIR=$(mktemp -d -t $(basename ${0}))
PATH=$PATH:"${TEMPDIR}"
@@ -72,6 +75,10 @@ function make_old_dest() {
defaults write "${DEST}/Contents/Info" KSVersion 0
cat >"${TEMPDIR}"/ksadmin <<EOF
#!/bin/sh
+if [ "\${1}" = "--ksadmin-version" ] ; then
+ echo "${KSADMIN_VERSION_LIE}"
+ exit 0
+fi
if [ -z "\${FAKE_SYSTEM_TICKET}" ] && [ "\${1}" = "-S" ] ; then
echo no system tix! >& 2
exit 1
@@ -93,6 +100,10 @@ function make_new_dest() {
defaults write "${RSRCDIR}/Info" KSVersion 0
cat >"${TEMPDIR}"/ksadmin <<EOF
#!/bin/sh
+if [ "\${1}" = "--ksadmin-version" ] ; then
+ echo "${KSADMIN_VERSION_LIE}"
+ exit 0
+fi
if [ -z "\${FAKE_SYSTEM_TICKET}" ] && [ "\${1}" = "-S" ] ; then
echo no system tix! >& 2
exit 1