| Index: chrome/app/app_mode_loader_mac.mm
|
| diff --git a/chrome/app/app_mode_loader_mac.mm b/chrome/app/app_mode_loader_mac.mm
|
| index a08a3082595c0e3990eebb023e78e84a8a2454fa..9a1a3917736856b1818ab82cfc97914f59a181e1 100644
|
| --- a/chrome/app/app_mode_loader_mac.mm
|
| +++ b/chrome/app/app_mode_loader_mac.mm
|
| @@ -9,139 +9,116 @@
|
| // framework side as possible).
|
|
|
| #include <dlfcn.h>
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <string.h>
|
|
|
| #include <CoreFoundation/CoreFoundation.h>
|
| #import <Foundation/Foundation.h>
|
|
|
| +#include "base/file_path.h"
|
| +#include "base/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/mac/foundation_util.h"
|
| +#include "base/mac/scoped_nsautorelease_pool.h"
|
| +#include "base/sys_string_conversions.h"
|
| +#import "chrome/common/mac/app_mode_chrome_locator.h"
|
| #include "chrome/common/mac/app_mode_common.h"
|
|
|
| namespace {
|
|
|
| -// Checks that condition |x| is true. If not, outputs |msg| (together with
|
| -// source filename and line number) and exits.
|
| -#define CHECK_MSG(x, msg) if (!(x)) check_msg_helper(__FILE__, __LINE__, msg);
|
| -void check_msg_helper(const char* file, int line, const char* msg) {
|
| - fprintf(stderr, "%s (%d): %s\n", file, line, msg);
|
| - exit(1);
|
| -}
|
| -
|
| -// Converts an NSString to a UTF8 C string (which is allocated, and may be freed
|
| -// using |free()|). If |s| is nil or can't produce such a string, this returns
|
| -// |NULL|.
|
| -char* NSStringToUTF8CString(NSString* s) {
|
| - CHECK_MSG([s isKindOfClass:[NSString class]], "expected an NSString");
|
| - const char* cstring = [s UTF8String];
|
| - return cstring ? strdup(cstring) : NULL;
|
| -}
|
| -
|
| -// Converts an NSString to a file-system representation C string (which is
|
| -// allocated, and may be freed using |free()|). If |s| is nil or can't produce
|
| -// such a string, this returns |NULL|.
|
| -char* NSStringToFSCString(NSString* s) {
|
| - CHECK_MSG([s isKindOfClass:[NSString class]], "expected an NSString");
|
| - const char* cstring = [s fileSystemRepresentation];
|
| - return cstring ? strdup(cstring) : NULL;
|
| -}
|
| -
|
| -} // namespace
|
| +void LoadFramework(void** cr_dylib, app_mode::ChromeAppModeInfo* info) {
|
| + using base::SysNSStringToUTF8;
|
| + using base::SysNSStringToUTF16;
|
| + using base::mac::CFToNSCast;
|
| + using base::mac::CFCastStrict;
|
| + using base::mac::NSToCFCast;
|
|
|
| -__attribute__((visibility("default")))
|
| -int main(int argc, char** argv) {
|
| - app_mode::ChromeAppModeInfo info;
|
| - info.major_version = 0; // v0.1
|
| - info.minor_version = 1;
|
| - info.argc = argc;
|
| - info.argv = argv;
|
| -
|
| - // The Cocoa APIs are a bit more convenient; for this an autorelease pool is
|
| - // needed.
|
| - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
| + base::mac::ScopedNSAutoreleasePool scoped_pool;
|
|
|
| // Get the current main bundle, i.e., that of the app loader that's running.
|
| NSBundle* app_bundle = [NSBundle mainBundle];
|
| - CHECK_MSG(app_bundle, "couldn't get loader bundle");
|
| + CHECK(app_bundle) << "couldn't get loader bundle";
|
|
|
| + // ** 1: Get path to outer Chrome bundle.
|
| // Get the bundle ID of the browser that created this app bundle.
|
| NSString* cr_bundle_id = [app_bundle
|
| objectForInfoDictionaryKey:app_mode::kBrowserBundleIDKey];
|
| - CHECK_MSG(cr_bundle_id, "couldn't get browser bundle ID");
|
| -
|
| - // Get the browser bundle path.
|
| - // TODO(viettrungluu): more fun
|
| - NSString* cr_bundle_path = [(NSString*)CFPreferencesCopyAppValue(
|
| - (CFStringRef)app_mode::kLastRunAppBundlePathPrefsKey,
|
| - (CFStringRef)cr_bundle_id) autorelease];
|
| - CHECK_MSG(cr_bundle_path, "couldn't get browser bundle path");
|
| -
|
| - // Get the browser bundle.
|
| - NSBundle* cr_bundle = [NSBundle bundleWithPath:cr_bundle_path];
|
| - CHECK_MSG(cr_bundle, "couldn't get browser bundle");
|
| -
|
| - // Get the current browser version.
|
| - NSString* cr_version =
|
| - [cr_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
| - CHECK_MSG(cr_version, "couldn't get browser version");
|
| -
|
| - // Get the current browser versioned directory.
|
| - NSArray* cr_versioned_path_components =
|
| - [NSArray arrayWithObjects:cr_bundle_path,
|
| - @"Contents",
|
| - @"Versions",
|
| - cr_version,
|
| - nil];
|
| - NSString* cr_versioned_path =
|
| - [[NSString pathWithComponents:cr_versioned_path_components]
|
| - stringByStandardizingPath];
|
| - CHECK_MSG(cr_versioned_path, "couldn't get browser versioned path");
|
| - // And copy it, since |cr_versioned_path| will go away with the pool.
|
| - info.chrome_versioned_path = NSStringToFSCString(cr_versioned_path);
|
| -
|
| - // Optional, so okay if it's NULL.
|
| - info.app_mode_bundle_path = NSStringToFSCString([app_bundle bundlePath]);
|
| + CHECK(cr_bundle_id) << "couldn't get browser bundle ID";
|
| +
|
| + // First check if Chrome exists at the last known location.
|
| + FilePath cr_bundle_path;
|
| + NSString* cr_bundle_path_ns =
|
| + [CFToNSCast(CFCastStrict<CFStringRef>(CFPreferencesCopyAppValue(
|
| + NSToCFCast(app_mode::kLastRunAppBundlePathPrefsKey),
|
| + NSToCFCast(cr_bundle_id)))) autorelease];
|
| + cr_bundle_path = base::mac::NSStringToFilePath(cr_bundle_path_ns);
|
| + bool found_bundle =
|
| + !cr_bundle_path.empty() && file_util::DirectoryExists(cr_bundle_path);
|
| +
|
| + if (!found_bundle) {
|
| + // If no such bundle path exists, try to search by bundle ID.
|
| + if (!app_mode::FindBundleById(cr_bundle_id, &cr_bundle_path)) {
|
| + // TODO(jeremy): Display UI to allow user to manually locate the Chrome
|
| + // bundle.
|
| + LOG(FATAL) << "Failed to locate bundle by identifier";
|
| + }
|
| + }
|
| +
|
| + // ** 2: Read information from the Chrome bundle.
|
| + string16 raw_version_str;
|
| + FilePath version_path;
|
| + FilePath framework_shlib_path;
|
| + if (!app_mode::GetChromeBundleInfo(cr_bundle_path, &raw_version_str,
|
| + &version_path, &framework_shlib_path)) {
|
| + LOG(FATAL) << "Couldn't ready Chrome bundle info";
|
| + }
|
| +
|
| + // ** 3: Fill in ChromeAppModeInfo.
|
| + info->chrome_versioned_path = version_path;
|
| + info->app_mode_bundle_path =
|
| + base::mac::NSStringToFilePath([app_bundle bundlePath]);
|
|
|
| // Read information about the this app shortcut from the Info.plist.
|
| // Don't check for null-ness on optional items.
|
| NSDictionary* info_plist = [app_bundle infoDictionary];
|
| - CHECK_MSG(info_plist, "couldn't get loader Info.plist");
|
| + CHECK(info_plist) << "couldn't get loader Info.plist";
|
|
|
| - info.app_mode_id = NSStringToUTF8CString(
|
| + info->app_mode_id = SysNSStringToUTF8(
|
| [info_plist objectForKey:app_mode::kCrAppModeShortcutIDKey]);
|
| - CHECK_MSG(info.app_mode_id, "couldn't get app shortcut ID");
|
| + CHECK(info->app_mode_id.size()) << "couldn't get app shortcut ID";
|
|
|
| - info.app_mode_short_name = NSStringToUTF8CString(
|
| + info->app_mode_short_name = SysNSStringToUTF16(
|
| [info_plist objectForKey:app_mode::kCrAppModeShortcutShortNameKey]);
|
|
|
| - info.app_mode_name = NSStringToUTF8CString(
|
| + info->app_mode_name = SysNSStringToUTF16(
|
| [info_plist objectForKey:app_mode::kCrAppModeShortcutNameKey]);
|
|
|
| - info.app_mode_url = NSStringToUTF8CString(
|
| + info->app_mode_url = SysNSStringToUTF8(
|
| [info_plist objectForKey:app_mode::kCrAppModeShortcutURLKey]);
|
| - CHECK_MSG(info.app_mode_url, "couldn't get app shortcut URL");
|
| -
|
| - // Get the framework path.
|
| - NSString* cr_bundle_exe =
|
| - [cr_bundle objectForInfoDictionaryKey:@"CFBundleExecutable"];
|
| - NSString* cr_framework_path =
|
| - [cr_versioned_path stringByAppendingPathComponent:
|
| - [cr_bundle_exe stringByAppendingString:@" Framework.framework"]];
|
| - cr_framework_path =
|
| - [cr_framework_path stringByAppendingPathComponent:
|
| - [cr_bundle_exe stringByAppendingString:@" Framework"]];
|
| + CHECK(info->app_mode_url.size()) << "couldn't get app shortcut URL";
|
|
|
| // Open the framework.
|
| - void* cr_dylib = dlopen([cr_framework_path fileSystemRepresentation],
|
| - RTLD_LAZY);
|
| - CHECK_MSG(cr_dylib, "couldn't load framework");
|
| + *cr_dylib = dlopen(framework_shlib_path.value().c_str(), RTLD_LAZY);
|
| + CHECK(cr_dylib) << "couldn't load framework: " << dlerror();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +__attribute__((visibility("default")))
|
| +int main(int argc, char** argv) {
|
| + app_mode::ChromeAppModeInfo info;
|
| +
|
| + // Hard coded info parameters.
|
| + info.major_version = 1; // v1.0
|
| + info.minor_version = 0;
|
| + info.argc = argc;
|
| + info.argv = argv;
|
|
|
| - // Drain the pool as late as possible.
|
| - [pool drain];
|
| + // Load the Chrome framework.
|
| + void *cr_dylib;
|
| + LoadFramework(&cr_dylib, &info);
|
|
|
| typedef int (*StartFun)(const app_mode::ChromeAppModeInfo*);
|
| StartFun ChromeAppModeStart = (StartFun)dlsym(cr_dylib, "ChromeAppModeStart");
|
| - CHECK_MSG(ChromeAppModeStart, "couldn't get entry point");
|
| + CHECK(ChromeAppModeStart) << "couldn't get entry point";
|
|
|
| // Exit instead of returning to avoid the the removal of |main()| from stack
|
| // backtraces under tail call optimization.
|
|
|