summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 15:51:57 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-14 15:51:57 +0000
commit41cd00a4e364aad2b9a53964684e554aa3b675e8 (patch)
tree65c85ff828574d1c06a0a66a4a6dd5c8dfcf447f /chrome
parent2b42f3d1a6ed5ba99f5b6f4ca907051040664f47 (diff)
downloadchromium_src-41cd00a4e364aad2b9a53964684e554aa3b675e8.zip
chromium_src-41cd00a4e364aad2b9a53964684e554aa3b675e8.tar.gz
chromium_src-41cd00a4e364aad2b9a53964684e554aa3b675e8.tar.bz2
Move the framework and helper application into a versioned directory in support
of unbreaking auto-update. BUG=14610 TEST= - The following bundles should be gone: - Chromium.app/Contents/Frameworks/Chromium Framework.framework - Chromium.app/Contents/Resources/Chromium Helper.app They should be replaced by: - Chromium.app/Contents/Versions/*/Chromium Framework.framework - Chromium.app/Contents/Versions/*/Chromium Helper.app - The application should continue to function properly and all tests should still pass. - The signed application should have the inner framework and helper application signed, and the outer application signed. The outer seal should permit unknown versions to be present in the Versions directory, but should protect the active versioned directory. - Auto-updating to an official build with this change should still work. Review URL: http://codereview.chromium.org/261031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28963 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/keystone_glue.mm (renamed from chrome/app/keystone_glue.m)21
-rwxr-xr-xchrome/app/make_mac_app_symlinks17
-rwxr-xr-xchrome/chrome.gyp167
-rw-r--r--chrome/common/child_process_host.cc59
-rw-r--r--chrome/common/chrome_constants.cc1
-rw-r--r--chrome/common/chrome_paths_internal.h11
-rw-r--r--chrome/common/chrome_paths_mac.mm50
-rw-r--r--chrome/tools/build/mac/app_resource_rules.plist.in55
-rwxr-xr-xchrome/tools/build/mac/clean_up_old_versions45
-rwxr-xr-xchrome/tools/build/mac/keystone_install.sh57
-rwxr-xr-xchrome/tools/build/mac/keystone_install_test.sh64
-rwxr-xr-xchrome/tools/build/mac/make_sign_sh30
-rwxr-xr-xchrome/tools/build/mac/remove_headers_from_framework31
-rw-r--r--chrome/tools/build/mac/sign.sh.in10
14 files changed, 453 insertions, 165 deletions
diff --git a/chrome/app/keystone_glue.m b/chrome/app/keystone_glue.mm
index 86f48ce..736972c 100644
--- a/chrome/app/keystone_glue.m
+++ b/chrome/app/keystone_glue.mm
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import "keystone_glue.h"
+#include "base/mac_util.h"
+#import "chrome/app/keystone_glue.h"
@interface KeystoneGlue(Private)
@@ -52,8 +53,7 @@ NSString *KSRegistrationRemoveExistingTag = @"";
@implementation KeystoneGlue
+ (id)defaultKeystoneGlue {
- // TODO(jrg): rename this file to .mm so I can use C++ and
- // make this type a base::SingletonObjC<KeystoneGlue>.
+ // TODO(jrg): use base::SingletonObjC<KeystoneGlue>
static KeystoneGlue* sDefaultKeystoneGlue = nil; // leaked
if (sDefaultKeystoneGlue == nil) {
@@ -78,7 +78,8 @@ NSString *KSRegistrationRemoveExistingTag = @"";
}
- (NSDictionary*)infoDictionary {
- return [[NSBundle mainBundle] infoDictionary];
+ // Use mac_util::MainAppBundle() to get the app framework's dictionary.
+ return [mac_util::MainAppBundle() infoDictionary];
}
- (void)loadParameters {
@@ -86,6 +87,8 @@ NSString *KSRegistrationRemoveExistingTag = @"";
NSString* url = [infoDictionary objectForKey:@"KSUpdateURL"];
NSString* product = [infoDictionary objectForKey:@"KSProductID"];
if (product == nil) {
+ // Use [NSBundle mainBundle] to fall back to the app's own bundle
+ // identifier, not the app framework's.
product = [[NSBundle mainBundle] bundleIdentifier];
}
NSString* version = [infoDictionary objectForKey:@"KSVersion"];
@@ -110,10 +113,10 @@ NSString *KSRegistrationRemoveExistingTag = @"";
if (!productID_ || !url_ || !version_)
return NO;
- // Load the KeystoneRegistration framework bundle.
- NSBundle* mainBundle = [NSBundle mainBundle];
+ // Load the KeystoneRegistration framework bundle if present. It lives
+ // inside the framework, so use mac_util::MainAppBundle();
NSString* ksrPath =
- [[mainBundle privateFrameworksPath]
+ [[mac_util::MainAppBundle() privateFrameworksPath]
stringByAppendingPathComponent:@"KeystoneRegistration.framework"];
NSBundle* ksrBundle = [NSBundle bundleWithPath:ksrPath];
[ksrBundle load];
@@ -129,6 +132,10 @@ NSString *KSRegistrationRemoveExistingTag = @"";
}
- (void)registerWithKeystone {
+ // The existence checks should use the path to the app bundle, not the
+ // app framework bundle, so use [NSBundle mainBundle] instead of
+ // mac_util::MainBundle().
+ //
// Only use new API if we can. This lets us land the new call
// before the new Keystone has been released.
//
diff --git a/chrome/app/make_mac_app_symlinks b/chrome/app/make_mac_app_symlinks
deleted file mode 100755
index 66353a95..0000000
--- a/chrome/app/make_mac_app_symlinks
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This script is intended to run from a "postbuild" action from within Xcode.
-# It sets up symbolic links for an app bundle's Frameworks directory. This is
-# intended to be used for app bundles that live within the Resources directory
-# of a larger app bundle, when the sub-app's Frameworks directory should point
-# to the enclosing app's.
-
-set -e
-
-CONTENTS_PATH="${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Contents"
-
-ln -fhs ../../../Frameworks "${CONTENTS_PATH}/Frameworks"
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 65c01f5..b36b2dc 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -12,8 +12,8 @@
},
'version_py_path': '<(version_py_path)',
'version_path': '<(version_path)',
- 'version_major_minor':
- '<!(python <(version_py_path) -f <(version_path) -t "@MAJOR@.@MINOR@")',
+ 'version_full':
+ '<!(python <(version_py_path) -f <(version_path) -t "@MAJOR@.@MINOR@.@BUILD@.@PATCH@")',
'version_build_patch':
'<!(python <(version_py_path) -f <(version_path) -t "@BUILD@.@PATCH@")',
@@ -3469,18 +3469,24 @@
'variables': {
'make_sign_sh_path': 'tools/build/mac/make_sign_sh',
'sign_sh_in_path': 'tools/build/mac/make_sign_sh',
+ 'app_resource_rules_in_path':
+ 'tools/build/mac/app_resource_rules.plist.in',
},
'inputs': [
'<(make_sign_sh_path)',
'<(sign_sh_in_path)',
+ '<(app_resource_rules_in_path)',
+ '<(version_path)',
],
'outputs': [
'<(mac_packaging_dir)/sign.sh',
+ '<(mac_packaging_dir)/app_resource_rules.plist',
],
'action': [
'<(make_sign_sh_path)',
'<(mac_packaging_sh_dir)',
'<(mac_product_name)',
+ '<(version_full)',
],
},
],
@@ -3498,9 +3504,6 @@
'CHROMIUM_CREATOR': '<(mac_creator)',
'CHROMIUM_SHORT_NAME': '<(branding)',
},
- 'mac_bundle_resources': [
- '<(PRODUCT_DIR)/<(mac_product_name) Helper.app',
- ],
'dependencies': [
'helper_app',
'infoplist_strings_tool',
@@ -3553,21 +3556,25 @@
],
'copies': [
{
- 'destination': '<(PRODUCT_DIR)/<(mac_product_name).app/Contents/Frameworks',
- 'files': ['<(PRODUCT_DIR)/<(mac_product_name) Framework.framework'],
+ 'destination': '<(PRODUCT_DIR)/<(mac_product_name).app/Contents/Versions/<(version_full)',
+ 'files': [
+ '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework',
+ '<(PRODUCT_DIR)/<(mac_product_name) Helper.app',
+ ],
},
],
'postbuilds': [
{
# 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 to not include any Breakpad information;
- # that all goes into the framework's Info.plist.
+ # 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.
'postbuild_name': 'Tweak Info.plist',
'action': ['<(DEPTH)/build/mac/tweak_app_infoplist',
'-b0',
- '-k<(mac_keystone)',
- '-s1', # Include Subversion information
+ '-k0',
+ '-s1',
'<(branding)'],
},
{
@@ -3579,6 +3586,13 @@
'postbuild_name': 'Clean up old resources',
'action': ['app/clean_mac_resources'],
},
+ {
+ 'postbuild_name': 'Clean up old versions',
+ 'action': [
+ 'tools/build/mac/clean_up_old_versions',
+ '<(version_full)'
+ ],
+ },
], # postbuilds
}, { # else: OS != "mac"
'conditions': [
@@ -4083,7 +4097,7 @@
['OS=="mac"', {
'sources': [
'app/keystone_glue.h',
- 'app/keystone_glue.m',
+ 'app/keystone_glue.mm',
'app/breakpad_mac_stubs.mm',
],
'sources!': [
@@ -4250,8 +4264,8 @@
'app/breakpad_mac_stubs.mm',
# *NO* files in chrome/app have unit tests (except keystone_glue)!!!
# It seems a waste to have an app_unittests target, so for now
- # I add keystone_glue.m explicitly to this target.
- 'app/keystone_glue.m',
+ # I add keystone_glue.mm explicitly to this target.
+ 'app/keystone_glue.mm',
'app/keystone_glue_unittest.mm',
# All unittests in browser, common, and renderer.
'browser/app_controller_mac_unittest.mm',
@@ -5041,7 +5055,8 @@
# version numbers.
'DYLIB_COMPATIBILITY_VERSION': '<(version_build_patch)',
'DYLIB_CURRENT_VERSION': '<(version_build_patch)',
- 'DYLIB_INSTALL_NAME_BASE': '@executable_path/../Frameworks',
+ 'DYLIB_INSTALL_NAME_BASE':
+ '@executable_path/../Versions/<(version_full)',
# FRAMEWORK_VERSION is used as the name of the directory in
# the framework's Versions directory that the Current symbolic
# link points to. Unfortunately, Xcode does not create this
@@ -5052,8 +5067,7 @@
# its default, 'A'. This is more than sufficient for our
# purposes, because the framework does not need to maintain
# any sort of stable public interface.
- # 'FRAMEWORK_VERSION':
- # '<(version_major_minor).<(version_build_patch)',
+ # 'FRAMEWORK_VERSION': '<(version_full)',
'CHROMIUM_BUNDLE_ID': '<(mac_bundle_id)',
'INFOPLIST_FILE': 'app/framework-Info.plist',
},
@@ -5062,7 +5076,7 @@
'app/chrome_dll_resource.h',
'app/chrome_exe_main.mm',
'app/keystone_glue.h',
- 'app/keystone_glue.m',
+ 'app/keystone_glue.mm',
],
# TODO(mark): Come up with a fancier way to do this. It should
# only be necessary to list framework-Info.plist once, not the
@@ -5227,13 +5241,15 @@
{
# Modify the Info.plist as needed. The script explains why
# this is needed. This is also done in the chrome target.
- # The framework does not need the Keystone or Subversion
- # keys, but it does need the Breakpad keys.
+ # The framework needs the Breakpad and Keystone keys if
+ # those features are enabled. It doesn't currently use the
+ # Subversion keys for anything, but this seems like a really
+ # good place to store them.
'postbuild_name': 'Tweak Info.plist',
'action': ['<(DEPTH)/build/mac/tweak_app_infoplist',
'-b<(mac_breakpad)',
- '-k0',
- '-s0',
+ '-k<(mac_keystone)',
+ '-s1',
'<(branding)'],
},
{
@@ -5242,10 +5258,12 @@
},
{
'postbuild_name': 'Symlink Libraries',
- 'action': ['ln',
- '-fhs',
- 'Versions/Current/Libraries',
- '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Libraries'],
+ 'action': [
+ 'ln',
+ '-fhs',
+ 'Versions/Current/Libraries',
+ '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Libraries'
+ ],
},
],
'copies': [
@@ -5284,6 +5302,35 @@
'app/breakpad_mac.h',
],
}], # mac_breakpad
+ ['mac_keystone==1', {
+ 'copies': [
+ {
+ 'destination':
+ '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Frameworks',
+ 'files': [
+ '../third_party/googlemac/Releases/Keystone/KeystoneRegistration.framework'
+ ],
+ },
+ ],
+ 'postbuilds': [
+ {
+ 'postbuild_name': 'Remove Keystone Headers',
+ 'action': [
+ 'tools/build/mac/remove_headers_from_framework',
+ '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Frameworks/KeystoneRegistration.framework',
+ ],
+ },
+ {
+ 'postbuild_name': 'Symlink Frameworks',
+ 'action': [
+ 'ln',
+ '-fhs',
+ 'Versions/Current/Frameworks',
+ '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Frameworks'
+ ],
+ },
+ ],
+ }], # mac_keystone
['branding=="Chrome"', {
'copies': [
{
@@ -5410,17 +5457,26 @@
],
'postbuilds': [
{
- 'postbuild_name': 'Make Symbolic Links',
- 'action': ['app/make_mac_app_symlinks'],
+ # The framework (chrome_dll) defines its load-time path
+ # (DYLIB_INSTALL_NAME_BASE) relative to the main executable
+ # (chrome). A different relative path needs to be used in
+ # helper_app.
+ 'postbuild_name': 'Fix Framework Link',
+ 'action': [
+ 'install_name_tool',
+ '-change',
+ '@executable_path/../Versions/<(version_full)/<(mac_product_name) Framework.framework/Versions/A/<(mac_product_name) Framework',
+ '@executable_path/../../../<(mac_product_name) Framework.framework/Versions/A/<(mac_product_name) Framework',
+ '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
+ ],
},
{
# Modify the Info.plist as needed. The script explains why this
# is needed. This is also done in the chrome and chrome_dll
- # targets. In this case, -b0 is used because Breakpad data is
- # not placed into the helper, it is only placed in the framework.
- # -k0 is used because Keystone never runs within the helper, only
- # within the main app. -s0 is used to avoid placing Subversion
- # data in the helper's Info.plist.
+ # targets. In this case, -b0 and -k0 are used because Breakpad
+ # and Keystone keys are never placed into the helper, only into
+ # the framework. -s0 is used because Subversion keys are only
+ # placed into the main app.
'postbuild_name': 'Tweak Info.plist',
'action': ['<(DEPTH)/build/mac/tweak_app_infoplist',
'-b0',
@@ -5441,7 +5497,7 @@
},
}],
],
- },
+ }, # target helper_app
{
# Convenience target to build a disk image.
'target_name': 'build_app_dmg',
@@ -5512,8 +5568,26 @@
],
},
'xcode_settings': {
+ 'DYLIB_COMPATIBILITY_VERSION': '<(version_build_patch)',
+ 'DYLIB_CURRENT_VERSION': '<(version_build_patch)',
'DYLIB_INSTALL_NAME_BASE': '@executable_path',
},
+ 'postbuilds': [
+ {
+ # The framework (chrome_dll) defines its load-time path
+ # (DYLIB_INSTALL_NAME_BASE) relative to the main executable
+ # (chrome). A different relative path needs to be used in
+ # plugin_carbon_interpose, which runs in the helper_app.
+ 'postbuild_name': 'Fix Framework Link',
+ 'action': [
+ 'install_name_tool',
+ '-change',
+ '@executable_path/../Versions/<(version_full)/<(mac_product_name) Framework.framework/Versions/A/<(mac_product_name) Framework',
+ '@executable_path/../../../<(mac_product_name) Framework.framework/Versions/A/<(mac_product_name) Framework',
+ '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
+ ],
+ },
+ ],
},
{
'target_name': 'infoplist_strings_tool',
@@ -5814,20 +5888,25 @@
'sources': [
'app/breakpad_mac_stubs.mm',
'app/keystone_glue.h',
- 'app/keystone_glue.m',
+ 'app/keystone_glue.mm',
],
'sources!': [
'<@(browser_tests_sources_exclude_on_mac)',
- ],
- # TODO(mark): We really want this for all non-static library targets,
- # but when we tried to pull it up to the common.gypi level, it broke
- # other things like the ui, startup, and page_cycler tests. *shrug*
- 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
+ ],
+ # TODO(mark): We really want this for all non-static library
+ # targets, but when we tried to pull it up to the common.gypi
+ # level, it broke other things like the ui, startup, and
+ # page_cycler tests. *shrug*
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [
+ '-Wl,-ObjC',
+ ],
+ },
}],
- ],
- },
- ],
- }],
+ ], # conditions
+ }, # target browser_tests
+ ], # targets
+ }], # OS!="win"
['OS=="win"',
{ 'targets': [
{
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc
index 6495fba..695ac18 100644
--- a/chrome/common/child_process_host.cc
+++ b/chrome/common/child_process_host.cc
@@ -15,6 +15,8 @@
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
@@ -83,61 +85,28 @@ ChildProcessHost::~ChildProcessHost() {
// static
FilePath ChildProcessHost::GetChildPath() {
- FilePath child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
- switches::kBrowserSubprocessPath);
+ static FilePath child_path;
+
if (!child_path.empty())
return child_path;
- FilePath path;
- PathService::Get(base::FILE_EXE, &path);
+ child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kBrowserSubprocessPath);
+ if (!child_path.empty())
+ return child_path;
#if !defined(OS_MACOSX)
// On most platforms, the child executable is the same as the current
// executable.
- return path;
+ PathService::Get(base::FILE_EXE, &child_path);
#else
// On the Mac, the child executable lives at a predefined location within
- // the current app bundle.
-
- // Figure out the current executable name. In a browser, this will be
- // "Chromium" or "Google Chrome". The child name will be the browser
- // executable name with " Helper" appended. The child app bundle name will
- // be that name with ".app" appended.
- FilePath::StringType child_exe_name = path.BaseName().value();
- const FilePath::StringType child_suffix = FILE_PATH_LITERAL(" Helper");
-
- if (child_exe_name.size() > child_suffix.size()) {
- size_t test_suffix_pos = child_exe_name.size() - child_suffix.size();
- const FilePath::CharType* test_suffix =
- child_exe_name.c_str() + test_suffix_pos;
- if (strcmp(test_suffix, child_suffix.c_str()) == 0) {
- // FILE_EXE already ends with the child suffix and therefore already
- // refers to the child process path. Just return it.
- return path;
- }
- }
-
- child_exe_name.append(child_suffix);
- FilePath::StringType child_app_name = child_exe_name;
- child_app_name.append(FILE_PATH_LITERAL(".app"));
- // The renderer app bundle lives in the browser app bundle's Resources
- // directory. Take off the executable name.
- path = path.DirName();
-
- // Take off the MacOS component, after verifying that's what's there.
- FilePath::StringType macos = path.BaseName().value();
- DCHECK_EQ(macos, FILE_PATH_LITERAL("MacOS"));
- path = path.DirName();
-
- // Append the components to get to the sub-app bundle's executable.
- path = path.Append(FILE_PATH_LITERAL("Resources"));
- path = path.Append(child_app_name);
- path = path.Append(FILE_PATH_LITERAL("Contents"));
- path = path.Append(FILE_PATH_LITERAL("MacOS"));
- path = path.Append(child_exe_name);
-
- return path;
+ // the app bundle's versioned directory.
+ child_path = chrome::GetVersionedDirectory().Append(
+ FilePath::FromWStringHack(chrome::kHelperProcessExecutablePath));
#endif // OS_MACOSX
+
+ return child_path;
}
// static
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 55ea255..5f8fc9a 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -44,7 +44,6 @@ const wchar_t kHelperProcessExecutablePath[] = L"chrome";
const wchar_t kBrowserProcessExecutablePath[] =
PRODUCT_STRING_W L".app/Contents/MacOS/" PRODUCT_STRING_W;
const wchar_t kHelperProcessExecutablePath[] =
- PRODUCT_STRING_W L".app/Contents/Resources/"
PRODUCT_STRING_W L" Helper.app/Contents/MacOS/" PRODUCT_STRING_W L" Helper";
#endif // OS_*
#if defined(OS_MACOSX)
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index 38d4dc8..dfaded7 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -38,6 +38,17 @@ bool GetUserDownloadsDirectory(FilePath* result);
bool GetUserDesktop(FilePath* result);
#if defined(OS_MACOSX)
+// The "versioned directory" is a directory in the browser .app bundle. It
+// contains the bulk of the application, except for the things that the system
+// requires be located at spepcific locations. The versioned directory is
+// in the .app at Contents/Versions/w.x.y.z.
+FilePath GetVersionedDirectory();
+
+// Most of the application is further contained within the framework. The
+// framework bundle is located within the versioned directory at a specific
+// path. The only components in the versioned directory not included in the
+// framework are things that also depend on the framework, such as the helper
+// app bundle.
FilePath GetFrameworkBundlePath();
#endif // OS_MACOSX
diff --git a/chrome/common/chrome_paths_mac.mm b/chrome/common/chrome_paths_mac.mm
index 3ddd796..beb22f2 100644
--- a/chrome/common/chrome_paths_mac.mm
+++ b/chrome/common/chrome_paths_mac.mm
@@ -66,6 +66,40 @@ bool GetUserDesktop(FilePath* result) {
return success;
}
+FilePath GetVersionedDirectory() {
+ static FilePath path;
+
+ if (path.empty()) {
+ // Start out with the path to the running .app.
+ NSBundle* app_bundle = [NSBundle mainBundle];
+ path = FilePath([[app_bundle bundlePath] fileSystemRepresentation]);
+
+ if (mac_util::IsBackgroundOnlyProcess()) {
+ // path identifies the helper .app in the browser .app's versioned
+ // directory. Go up one level to get to the browser .app's versioned
+ // directory.
+ path = path.DirName();
+ } else {
+ // path identifies the browser .app. Go into its versioned directory.
+ // TODO(mark): Here, |version| comes from the outer .app bundle's
+ // Info.plist. In the event of an incomplete update, it may be possible
+ // for this value to be incorrect. Consider the case where the updater
+ // is able to update one, but not both, of the executable and the
+ // Info.plist. The executable may load one version of the framework,
+ // and the Info.plist may refer to another version. Ideally, the
+ // version would be available in a compile-time constant, or there would
+ // be a better way to detect the loaded framework version at runtime.
+ NSString* version =
+ [app_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+ path = path.Append("Contents").
+ Append("Versions").
+ Append([version fileSystemRepresentation]);
+ }
+ }
+
+ return path;
+}
+
FilePath GetFrameworkBundlePath() {
// It's tempting to use +[NSBundle bundleWithIdentifier:], but it's really
// slow (about 30ms on 10.5 and 10.6), despite Apple's documentation stating
@@ -76,21 +110,9 @@ FilePath GetFrameworkBundlePath() {
// needed to compute the framework's path are also effectively free, so that
// is the approach that is used here.
- // Start out with the path to the running .app.
- FilePath path([[[NSBundle mainBundle] bundlePath] fileSystemRepresentation]);
-
- if (mac_util::IsBackgroundOnlyProcess()) {
- // path identifies the helper .app in the browser .app's Contents/Resources
- // directory. Go up two levels to get to the browser's Contents directory.
- path = path.DirName().DirName();
- } else {
- // path identifies the browser .app. Go into the Contents directory.
- path = path.Append("Contents");
- }
-
// The framework bundle is at a known path and name from the browser .app's
- // Contents directory.
- return path.Append("Frameworks").Append(kFrameworkName);
+ // versioned directory.
+ return GetVersionedDirectory().Append(kFrameworkName);
}
} // namespace chrome
diff --git a/chrome/tools/build/mac/app_resource_rules.plist.in b/chrome/tools/build/mac/app_resource_rules.plist.in
new file mode 100644
index 0000000..d629044
--- /dev/null
+++ b/chrome/tools/build/mac/app_resource_rules.plist.in
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>rules</key>
+ <dict>
+ <key>^PkgInfo$</key>
+ <true/>
+ <key>^MacOS/</key>
+ <true/>
+ <key>^Resources/</key>
+ <true/>
+ <key>^Versions/</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>10</real>
+ </dict>
+ <key>^Versions/@VERSION_REGEX@/</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^Resources/.+\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>30</real>
+ </dict>
+ <key>^Versions/@VERSION_REGEX@/.+/Resources/.+\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>30</real>
+ </dict>
+ <key>^Versions/@VERSION_REGEX@/.+/Resources Disabled/</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>40</real>
+ </dict>
+ <key>/\.DS_Store$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>50</real>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/chrome/tools/build/mac/clean_up_old_versions b/chrome/tools/build/mac/clean_up_old_versions
new file mode 100755
index 0000000..b970a15
--- /dev/null
+++ b/chrome/tools/build/mac/clean_up_old_versions
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Remove old versioned directories from an .app bundle. The built-up bundle
+# only needs to contain the current versioned directory.
+
+set -e
+
+if [ $# -ne 1 ] ; then
+ echo "usage: ${0} VERSION" >& 2
+ exit 1
+fi
+
+VERSION="${1}"
+CONTENTS_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
+VERSIONED_DIR="${CONTENTS_DIR}/Versions"
+CURRENT_VERSIONED_DIR="${VERSIONED_DIR}/${VERSION}"
+
+for dir in "${VERSIONED_DIR}/"* ; do
+ if [ "${dir}" != "${CURRENT_VERSIONED_DIR}" ] ; then
+ rm -rf "${dir}"
+ fi
+done
+
+# Older builds did not use a versioned directory, and instead placed the
+# framework, helper app, and other components directly within the main app
+# bundle. To keep incremental developer builds relatively pristine and
+# equivalent to clean builds, these old components need to be cleaned up if
+# present.
+# Frameworks includes the app framework (Chromium Framework.framework or
+# Google Chrome Framework.framework) and, if Keystone-enabled,
+# KeystoneRegistration.framework. To simplify this script, it removes the
+# helper app at its old location under either of the supported branding names.
+# TODO(mark): Remove the following section some time after October 27, 2009,
+# allowing two weeks for the transition.
+
+rm -rf "${CONTENTS_DIR}/Frameworks" \
+ "${CONTENTS_DIR}/Resources/Chromium Helper.app" \
+ "${CONTENTS_DIR}/Resources/Google Chrome Helper.app" \
+ "${CONTENTS_DIR}/MacOS/libavcodec.52.dylib" \
+ "${CONTENTS_DIR}/MacOS/libavformat.52.dylib" \
+ "${CONTENTS_DIR}/MacOS/libavutil.50.dylib"
diff --git a/chrome/tools/build/mac/keystone_install.sh b/chrome/tools/build/mac/keystone_install.sh
index 173875a..7ef7368 100755
--- a/chrome/tools/build/mac/keystone_install.sh
+++ b/chrome/tools/build/mac/keystone_install.sh
@@ -27,28 +27,46 @@ if [ $# -lt 1 ] || [ ! -d "${1}" ]; then
fi
# Who we are.
-APP_NAME="Google Chrome.app"
+PRODUCT_NAME="Google Chrome"
+APP_NAME="${PRODUCT_NAME}.app"
+FRAMEWORK_NAME="${PRODUCT_NAME} Framework.framework"
SRC="${1}/${APP_NAME}"
# Sanity, make sure that there's something to copy from.
-if [ ! -d "${SRC}" ]; then
+if [ -z "${SRC}" ] || [ ! -d "${SRC}" ]; then
exit 10
fi
-# Figure out where we're going.
-PRODUCT_ID=$(defaults read "${SRC}/Contents/Info" KSProductID || exit 3)
+# Figure out where we're going. Determine the application version to be
+# installed, use that to locate the framework, and then look inside the
+# framework for the Keystone product ID.
+APP_VERSION_KEY="CFBundleShortVersionString"
+UPD_VERSION_APP=$(defaults read "${SRC}/Contents/Info" "${APP_VERSION_KEY}" ||
+ exit 10)
+UPD_KS_PLIST="${SRC}/Contents/Versions/${UPD_VERSION_APP}/${FRAMEWORK_NAME}/Resources/Info"
+PRODUCT_ID=$(defaults read "${UPD_KS_PLIST}" KSProductID || exit 10)
DEST=$(ksadmin -pP "${PRODUCT_ID}" | grep xc= | sed -E 's/.+path=(.+)>$/\1/g')
# More sanity checking.
-if [ -z "${SRC}" ] || [ -z "${DEST}" ] || [ ! -d $(dirname "${DEST}") ]; then
+if [ -z "${DEST}" ] || [ ! -d "$(dirname "${DEST}")" ]; then
exit 2
fi
-# Read old version to help confirm install happiness
-OLD_VERSION=$(defaults read "${DEST}/Contents/Info" KSVersion || exit 3)
+# Read old version to help confirm install happiness. Older versions kept
+# the KSVersion key in the application's Info.plist. Newer versions keep it
+# in the versioned framework's Info.plist.
+KS_VERSION_KEY="KSVersion"
+OLD_VERSION_APP=$(defaults read "${DEST}/Contents/Info" "${APP_VERSION_KEY}" ||
+ defaults read "${DEST}/Contents/Info" "${KS_VERSION_KEY}" ||
+ exit 3)
+OLD_KS_PLIST="${DEST}/Contents/Versions/${OLD_VERSION_APP}/${FRAMEWORK_NAME}/Resources/Info"
+if [ ! -e "${OLD_KS_PLIST}.plist" ] ; then
+ OLD_KS_PLIST="${DEST}/Contents/Info"
+fi
+OLD_VERSION_KS=$(defaults read "${OLD_KS_PLIST}" "${KS_VERSION_KEY}" || exit 3)
# Make sure we have permission to write the destination
-DEST_DIRECTORY=$(dirname "${DEST}")
+DEST_DIRECTORY="$(dirname "${DEST}")"
if [ ! -w "${DEST_DIRECTORY}" ]; then
exit 4
fi
@@ -56,18 +74,21 @@ fi
# This usage will preserve any changes the user made to the application name.
# TODO(jrg): this may choke a running Chrome.app; be smarter.
# Note: If the rsync fails we do not update the ticket version.
-rsync -a --delete "${SRC}/" "${DEST}/" || exit 5
-
-# Read the new values (e.g. version)
-VERSION=$(defaults read "${DEST}/Contents/Info" KSVersion || exit 6)
-URL=$(defaults read "${DEST}/Contents/Info" KSUpdateURL || exit 6)
+rsync -ac --delete "${SRC}/" "${DEST}/" || exit 5
+
+# Read the new values (e.g. version). Get the installed application version
+# to get the path to the framework, where the Keystone keys are stored.
+NEW_VERSION_APP=$(defaults read "${DEST}/Contents/Info" "${APP_VERSION_KEY}" ||
+ exit 6)
+NEW_KS_PLIST="${DEST}/Contents/Versions/${NEW_VERSION_APP}/${FRAMEWORK_NAME}/Resources/Info"
+NEW_VERSION_KS=$(defaults read "${NEW_KS_PLIST}" "${KS_VERSION_KEY}" || exit 6)
+URL=$(defaults read "${NEW_KS_PLIST}" KSUpdateURL || exit 6)
# The channel ID is optional. Suppress stderr to prevent Keystone from seeing
# possible error output.
-CHANNEL_ID=$(defaults read "${DEST}/Contents/Info" KSChannelID 2>/dev/null || \
- true)
+CHANNEL_ID=$(defaults read "${NEW_KS_PLIST}" KSChannelID 2>/dev/null || true)
# Compare old and new versions. If they are equal we failed somewhere.
-if [ "${OLD_VERSION}" = "${VERSION}" ]; then
+if [ "${OLD_VERSION_KS}" = "${NEW_VERSION_KS}" ]; then
exit 7
fi
@@ -83,13 +104,13 @@ fi
# patterns for any support checks we need.
ksadmin --register \
-P "${PRODUCT_ID}" \
- --version "${VERSION}" \
+ --version "${NEW_VERSION_KS}" \
--xcpath "${DEST}" \
--url "${URL}" \
--tag "${CHANNEL_ID}" || \
ksadmin --register \
-P "${PRODUCT_ID}" \
- --version "${VERSION}" \
+ --version "${NEW_VERSION_KS}" \
--xcpath "${DEST}" \
--url "${URL}" || exit 8
diff --git a/chrome/tools/build/mac/keystone_install_test.sh b/chrome/tools/build/mac/keystone_install_test.sh
index b72a9d4..6ddf9ca9 100755
--- a/chrome/tools/build/mac/keystone_install_test.sh
+++ b/chrome/tools/build/mac/keystone_install_test.sh
@@ -18,7 +18,9 @@ if [ ! -f "${INSTALLER}" ]; then
fi
# What I test
-APPNAME="Google Chrome.app"
+PRODNAME="Google Chrome"
+APPNAME="${PRODNAME}.app"
+FWKNAME="${PRODNAME} Framework.framework"
# Temp directory to be used as the disk image (source)
TEMPDIR=$(mktemp -d ${TMPDIR}/$(basename ${0}).XXXXXX)
@@ -61,15 +63,11 @@ function pass_installer() {
fi
}
-# Most of the setup for an install source and dest
-function make_basic_src_and_dest() {
- chmod ugo+w "${TEMPDIR}"
- rm -rf "${TEMPDIR}"
- mkdir -p "${TEMPDIR}/${APPNAME}/Contents"
- defaults write "${TEMPDIR}/${APPNAME}/Contents/Info" \
- KSProductID "com.google.Chrome"
- defaults write "${TEMPDIR}/${APPNAME}/Contents/Info" KSVersion 1
+# Make an old-style destination directory, to test updating from old-style
+# versions to new-style versions.
+function make_old_dest() {
DEST="${TEMPDIR}"/Dest.app
+ rm -rf "${DEST}"
mkdir -p "${DEST}"/Contents
defaults write "${DEST}/Contents/Info" KSVersion 0
cat >"${TEMPDIR}"/ksadmin <<EOF
@@ -80,6 +78,42 @@ EOF
chmod u+x "${TEMPDIR}"/ksadmin
}
+# Make a new-style destination directory, to test updating between new-style
+# versions.
+function make_new_dest() {
+ DEST="${TEMPDIR}"/Dest.app
+ rm -rf "${DEST}"
+ RSRCDIR="${DEST}/Contents/Versions/0/${FWKNAME}/Resources"
+ mkdir -p "${RSRCDIR}"
+ defaults write "${DEST}/Contents/Info" CFBundleShortVersionString 0
+ defaults write "${RSRCDIR}/Info" KSVersion 0
+ cat >"${TEMPDIR}"/ksadmin <<EOF
+#!/bin/sh
+echo "echo xc=<blah path=$DEST>"
+exit 0
+EOF
+ chmod u+x "${TEMPDIR}"/ksadmin
+}
+
+# Make a simple source directory - the update that is to be applied
+function make_src() {
+ chmod ugo+w "${TEMPDIR}"
+ rm -rf "${TEMPDIR}/${APPNAME}"
+ RSRCDIR="${TEMPDIR}/${APPNAME}/Contents/Versions/1/${FWKNAME}/Resources"
+ mkdir -p "${RSRCDIR}"
+ defaults write "${TEMPDIR}/${APPNAME}/Contents/Info" \
+ CFBundleShortVersionString "1"
+ defaults write "${RSRCDIR}/Info" \
+ KSProductID "com.google.Chrome"
+ defaults write "${RSRCDIR}/Info" \
+ KSVersion "2"
+}
+
+function make_basic_src_and_dest() {
+ make_src
+ make_new_dest
+}
+
fail_installer "No source anything"
mkdir "${TEMPDIR}"/"${APPNAME}"
@@ -92,9 +126,17 @@ fail_installer "Writable dest directory"
make_basic_src_and_dest
fail_installer "Was no KSUpdateURL in dest after copy"
+make_src
+make_old_dest
+defaults write \
+ "${TEMPDIR}/${APPNAME}/Contents/Versions/1/${FWKNAME}/Resources/Info" \
+ KSUpdateURL "http://foo.bar"
+pass_installer "Old-style update"
+
make_basic_src_and_dest
-defaults write "${TEMPDIR}/${APPNAME}/Contents/Info" \
- KSUpdateURL "http://foo.bar"
+defaults write \
+ "${TEMPDIR}/${APPNAME}/Contents/Versions/1/${FWKNAME}/Resources/Info" \
+ KSUpdateURL "http://foo.bar"
pass_installer "ALL"
cleanup_tempdir
diff --git a/chrome/tools/build/mac/make_sign_sh b/chrome/tools/build/mac/make_sign_sh
index 115882c..db6e1c2 100755
--- a/chrome/tools/build/mac/make_sign_sh
+++ b/chrome/tools/build/mac/make_sign_sh
@@ -5,24 +5,44 @@
# found in the LICENSE file.
# This script creates sign.sh, the script that will be used to sign the
-# application bundle and inner bundles. sign.sh is placed in the Packaging
+# application bundle and inner bundles. It also creates auxiliary files that
+# sign.sh needs to do its job, such as the custom resource rules used to sign
+# the outermost application bundle. These files are placed in the Packaging
# directory next to the .app bundle. The packaging system is expected to run
# sign.sh to sign everything.
set -e
-if [ $# -ne 2 ] ; then
- echo "usage: ${0} PACKAGING_DIR MAC_PRODUCT_NAME" >& 2
+if [ $# -ne 3 ] ; then
+ echo "usage: ${0} PACKAGING_DIR MAC_PRODUCT_NAME VERSION" >& 2
exit 1
fi
PACKAGING_DIR="${1}"
MAC_PRODUCT_NAME="${2}"
-SIGN_SH_IN_FILE="$(dirname "${0}")/sign.sh.in"
+VERSION="${3}"
+
+INPUT_DIR="$(dirname "${0}")"
+SIGN_SH_IN_FILE="${INPUT_DIR}/sign.sh.in"
SIGN_SH_FILE="${PACKAGING_DIR}/sign.sh"
+BROWSER_APP_RULES_IN_FILE="${INPUT_DIR}/app_resource_rules.plist.in"
+BROWSER_APP_RULES_FILE="${PACKAGING_DIR}/app_resource_rules.plist"
+
+# Double-backslash each dot: one backslash belongs in the regular expression,
+# and the other backslash tells sed not to treat the first backslash
+# specially.
+VERSION_REGEX="$(echo "${VERSION}" | sed -e 's/\./\\\\./g')"
mkdir -p "${PACKAGING_DIR}"
sed -e "s/@MAC_PRODUCT_NAME@/${MAC_PRODUCT_NAME}/g" \
+ -e "s/@VERSION@/${VERSION}/g" \
+ -e "s/@VERSION_REGEX@/${VERSION_REGEX}/g" \
< "${SIGN_SH_IN_FILE}" \
> "${SIGN_SH_FILE}"
-chmod a+rx "${SIGN_SH_FILE}"
+chmod +x "${SIGN_SH_FILE}"
+
+sed -e "s/@MAC_PRODUCT_NAME@/${MAC_PRODUCT_NAME}/g" \
+ -e "s/@VERSION@/${VERSION}/g" \
+ -e "s/@VERSION_REGEX@/${VERSION_REGEX}/g" \
+ < "${BROWSER_APP_RULES_IN_FILE}" \
+ > "${BROWSER_APP_RULES_FILE}"
diff --git a/chrome/tools/build/mac/remove_headers_from_framework b/chrome/tools/build/mac/remove_headers_from_framework
new file mode 100755
index 0000000..c48fd1f
--- /dev/null
+++ b/chrome/tools/build/mac/remove_headers_from_framework
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Frameworks included in an application for distribution aren't used for
+# development, and don't need to bundle any headers.
+
+set -e
+
+if [ $# -ne 1 ] ; then
+ echo "usage: ${0} FRAMEWORK" >& 2
+ exit 1
+fi
+
+FRAMEWORK="${1}"
+
+rm -rf -- "${FRAMEWORK}/Versions/Current/Headers" \
+ "${FRAMEWORK}/Versions/Current/PrivateHeaders" \
+ "${FRAMEWORK}/Headers" \
+ "${FRAMEWORK}/PrivateHeaders"
+
+# Remove other-versioned headers after current-version headers, in case Current
+# is a symbolic link to another version, as is the usual case. If everything
+# was done in a single invocation, the shell would do the wildcard expansion
+# first, and rm would try (and fail) to remove the same directory twice, such
+# as Versions/Current/Headers and Versions/A/Headers when Versions/Current is
+# a symbolic link for A.
+rm -rf -- "${FRAMEWORK}"/Versions/*/Headers \
+ "${FRAMEWORK}"/Versions/*/PrivateHeaders
diff --git a/chrome/tools/build/mac/sign.sh.in b/chrome/tools/build/mac/sign.sh.in
index 41c8b58..07a7593 100644
--- a/chrome/tools/build/mac/sign.sh.in
+++ b/chrome/tools/build/mac/sign.sh.in
@@ -18,13 +18,16 @@ APP_PATH="${1}"
CODESIGN_KEYCHAIN="${2}"
CODESIGN_ID="${3}"
+# Use custom resource rules for the browser application.
+BROWSER_APP_RULES="$(dirname "${0}")/app_resource_rules.plist"
+
# An .app bundle to be signed can be signed directly. Signging a framework
# bundle requires that each version within be signed individually.
# http://developer.apple.com/mac/library/technotes/tn2007/tn2206.html#TNTAG13
BROWSER_APP="${APP_PATH}"
-FRAMEWORK="${BROWSER_APP}/Contents/Frameworks/@MAC_PRODUCT_NAME@ Framework.framework/Versions/A"
-HELPER_APP="${BROWSER_APP}/Contents/Resources/@MAC_PRODUCT_NAME@ Helper.app"
+FRAMEWORK="${BROWSER_APP}/Contents/Versions/@VERSION@/@MAC_PRODUCT_NAME@ Framework.framework/Versions/A"
+HELPER_APP="${BROWSER_APP}/Contents/Versions/@VERSION@/@MAC_PRODUCT_NAME@ Helper.app"
echo "${0}: signing..."
@@ -33,7 +36,8 @@ echo "${0}: signing..."
codesign -s "${CODESIGN_ID}" --keychain "${CODESIGN_KEYCHAIN}" "${FRAMEWORK}"
codesign -s "${CODESIGN_ID}" --keychain "${CODESIGN_KEYCHAIN}" "${HELPER_APP}"
-codesign -s "${CODESIGN_ID}" --keychain "${CODESIGN_KEYCHAIN}" "${BROWSER_APP}"
+codesign -s "${CODESIGN_ID}" --keychain "${CODESIGN_KEYCHAIN}" \
+ "${BROWSER_APP}" --resource-rules "${BROWSER_APP_RULES}"
# Verify everything to ensure that signing the outer bundle didn't break an
# inner bundle.