summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjackhou@chromium.org <jackhou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-18 18:26:38 +0000
committerjackhou@chromium.org <jackhou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-18 18:26:38 +0000
commit5bbfbae20e9c1871d100d649c4c59e39e4264da4 (patch)
tree9a4b7e065f65071173eea850c3cfa8eddad195c6
parent34f1c4212da0da25773254f32b3c8f76fb56af45 (diff)
downloadchromium_src-5bbfbae20e9c1871d100d649c4c59e39e4264da4.zip
chromium_src-5bbfbae20e9c1871d100d649c4c59e39e4264da4.tar.gz
chromium_src-5bbfbae20e9c1871d100d649c4c59e39e4264da4.tar.bz2
[Mac] Rebuild app shims when they fail to dyload Chrome Framework.
This also changes app_mode_loader to start Chrome with --app-shim-error only when it was started by Chrome or if it is the app_list shim. When started by the user, it launches Chrome with --app-id. This simplifies how Chrome handles --app-shim-error. It does not need to load the profile or app extension, and rebuilding the shim does not block launching the app. BUG=353047 Review URL: https://codereview.chromium.org/265163006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278126 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/app_mode_loader_mac.mm61
-rw-r--r--chrome/browser/ui/app_list/app_list_service.h3
-rw-r--r--chrome/browser/ui/app_list/app_list_service_disabled.cc2
-rw-r--r--chrome/browser/ui/app_list/app_list_service_impl.h4
-rw-r--r--chrome/browser/ui/app_list/app_list_service_mac.h2
-rw-r--r--chrome/browser/ui/startup/startup_browser_creator.cc9
-rw-r--r--chrome/browser/ui/views/app_list/linux/app_list_service_linux.h2
-rw-r--r--chrome/browser/ui/views/app_list/win/app_list_service_win.h2
-rw-r--r--chrome/browser/web_applications/web_app.cc64
-rw-r--r--chrome/browser/web_applications/web_app.h10
-rw-r--r--chrome/browser/web_applications/web_app_mac.h7
-rw-r--r--chrome/browser/web_applications/web_app_mac.mm74
-rw-r--r--chrome/chrome.gyp5
-rw-r--r--chrome/common/mac/app_mode_chrome_locator.h2
-rw-r--r--chrome/common/mac/app_mode_chrome_locator.mm26
-rw-r--r--chrome/common/mac/app_mode_chrome_locator_unittest.mm7
-rw-r--r--chrome/common/mac/app_mode_common.h6
-rw-r--r--chrome/common/mac/app_mode_common.mm1
18 files changed, 213 insertions, 74 deletions
diff --git a/chrome/app/app_mode_loader_mac.mm b/chrome/app/app_mode_loader_mac.mm
index 402aea8..7a489eb 100644
--- a/chrome/app/app_mode_loader_mac.mm
+++ b/chrome/app/app_mode_loader_mac.mm
@@ -20,7 +20,9 @@
#include "base/mac/foundation_util.h"
#include "base/mac/launch_services_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/process/launch.h"
#include "base/strings/sys_string_conversions.h"
+#include "chrome/common/chrome_switches.h"
#import "chrome/common/mac/app_mode_chrome_locator.h"
#include "chrome/common/mac/app_mode_common.h"
@@ -67,11 +69,15 @@ int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) {
}
// ** 2: Read information from the Chrome bundle.
+ base::FilePath executable_path;
base::string16 raw_version_str;
base::FilePath version_path;
base::FilePath framework_shlib_path;
- if (!app_mode::GetChromeBundleInfo(cr_bundle_path, &raw_version_str,
- &version_path, &framework_shlib_path)) {
+ if (!app_mode::GetChromeBundleInfo(cr_bundle_path,
+ &executable_path,
+ &raw_version_str,
+ &version_path,
+ &framework_shlib_path)) {
LOG(FATAL) << "Couldn't ready Chrome bundle info";
}
base::FilePath app_mode_bundle_path =
@@ -115,28 +121,53 @@ int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) {
LOG(ERROR) << "Couldn't load framework: " << dlerror();
}
- if (ChromeAppModeStart) {
+ if (ChromeAppModeStart)
return ChromeAppModeStart(info);
- } else {
- LOG(ERROR) << "Loading Chrome failed, launching with command line.";
- // Launch Chrome instead and have it update this app_mode_loader bundle.
- CommandLine command_line(CommandLine::NO_PROGRAM);
- command_line.AppendSwitchPath(app_mode::kAppShimError,
- app_mode_bundle_path);
- if (!base::mac::OpenApplicationWithPath(
- cr_bundle_path, command_line, kLSLaunchDefaults, NULL)) {
- LOG(ERROR) << "Could not launch Chrome from: " << cr_bundle_path.value();
- return 1;
- }
- return 0;
+ LOG(ERROR) << "Loading Chrome failed, launching Chrome with command line";
+ CommandLine command_line(executable_path);
+ // The user_data_dir from the plist is actually the app data dir.
+ command_line.AppendSwitchPath(
+ switches::kUserDataDir,
+ info->user_data_dir.DirName().DirName().DirName());
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ app_mode::kLaunchedByChromeProcessId) ||
+ info->app_mode_id == app_mode::kAppListModeId) {
+ // Pass --app-shim-error to have Chrome rebuild this shim.
+ // If Chrome has rebuilt this shim once already, then rebuilding doesn't fix
+ // the problem, so don't try again.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ app_mode::kLaunchedAfterRebuild)) {
+ command_line.AppendSwitchPath(app_mode::kAppShimError,
+ app_mode_bundle_path);
+ }
+ } else {
+ // If the shim was launched directly (instead of by Chrome), first ask
+ // Chrome to launch the app. Chrome will launch the shim again, the same
+ // error will occur and be handled above. This approach allows the app to be
+ // started without blocking on fixing the shim and guarantees that the
+ // profile is loaded when Chrome receives --app-shim-error.
+ command_line.AppendSwitchPath(switches::kProfileDirectory,
+ info->profile_dir);
+ command_line.AppendSwitchASCII(switches::kAppId, info->app_mode_id);
+ }
+ // Launch the executable directly since base::mac::OpenApplicationWithPath
+ // uses LSOpenApplication which doesn't pass command line arguments if the
+ // application is already running.
+ if (!base::LaunchProcess(command_line, base::LaunchOptions(), NULL)) {
+ LOG(ERROR) << "Could not launch Chrome: "
+ << command_line.GetCommandLineString();
+ return 1;
}
+
+ return 0;
}
} // namespace
__attribute__((visibility("default")))
int main(int argc, char** argv) {
+ CommandLine::Init(argc, argv);
app_mode::ChromeAppModeInfo info;
// Hard coded info parameters.
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index 91fbe7f..ce92300 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -103,6 +103,9 @@ class AppListService {
// Returns a pointer to the platform specific AppListControllerDelegate.
virtual AppListControllerDelegate* GetControllerDelegate() = 0;
+ // Create a platform-specific shortcut for the app list.
+ virtual void CreateShortcut() = 0;
+
protected:
AppListService() {}
virtual ~AppListService() {}
diff --git a/chrome/browser/ui/app_list/app_list_service_disabled.cc b/chrome/browser/ui/app_list/app_list_service_disabled.cc
index 4e7b5d1..5261459 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -45,6 +45,8 @@ class AppListServiceDisabled : public AppListService {
return NULL;
}
+ virtual void CreateShortcut() OVERRIDE {}
+
virtual gfx::NativeWindow GetAppListWindow() OVERRIDE {
return NULL;
}
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.h b/chrome/browser/ui/app_list/app_list_service_impl.h
index 9cc514c..6fe68ae 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -48,6 +48,7 @@ class AppListServiceImpl : public AppListService,
virtual void AutoShowForProfile(Profile* requested_profile) OVERRIDE;
virtual void EnableAppList(Profile* initial_profile,
AppListEnableSource enable_source) OVERRIDE;
+ virtual void CreateShortcut() OVERRIDE;
protected:
AppListServiceImpl();
@@ -61,9 +62,6 @@ class AppListServiceImpl : public AppListService,
// list, and records UMA stats delayed from a previous Chrome process.
void PerformStartupChecks(Profile* initial_profile);
- // Create a platform-specific shortcut for the app list.
- virtual void CreateShortcut();
-
private:
static void SendAppListStats();
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.h b/chrome/browser/ui/app_list/app_list_service_mac.h
index 9247531..4f0646d 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.h
+++ b/chrome/browser/ui/app_list/app_list_service_mac.h
@@ -62,8 +62,6 @@ class AppListServiceMac : public AppListServiceImpl,
virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
virtual AppListControllerDelegate* GetControllerDelegate() OVERRIDE;
virtual Profile* GetCurrentAppListProfile() OVERRIDE;
-
- // AppListServiceImpl overrides:
virtual void CreateShortcut() OVERRIDE;
// AppShimHandler overrides:
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index defd5bd..4393aa0 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -85,6 +85,10 @@
#include "ui/events/x/touch_factory_x11.h"
#endif
+#if defined(OS_MACOSX)
+#include "chrome/browser/web_applications/web_app_mac.h"
+#endif
+
#if defined(ENABLE_FULL_PRINTING)
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
@@ -558,6 +562,11 @@ bool StartupBrowserCreator::ProcessCmdLineImpl(
ui::TouchFactory::SetTouchDeviceListFromCommandLine();
#endif
+#if defined(OS_MACOSX)
+ if (web_app::MaybeRebuildShortcut(command_line))
+ return true;
+#endif
+
if (!process_startup &&
command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
// Only handle --dump-browser-histograms from a rendezvous. In this case, do
diff --git a/chrome/browser/ui/views/app_list/linux/app_list_service_linux.h b/chrome/browser/ui/views/app_list/linux/app_list_service_linux.h
index 1dc35f2..dc32e83 100644
--- a/chrome/browser/ui/views/app_list/linux/app_list_service_linux.h
+++ b/chrome/browser/ui/views/app_list/linux/app_list_service_linux.h
@@ -19,7 +19,7 @@ class AppListServiceLinux : public AppListServiceViews,
static AppListServiceLinux* GetInstance();
- // AppListServiceImpl overrides:
+ // AppListService overrides:
virtual void CreateShortcut() OVERRIDE;
// app_list::AppListViewObserver overrides:
diff --git a/chrome/browser/ui/views/app_list/win/app_list_service_win.h b/chrome/browser/ui/views/app_list/win/app_list_service_win.h
index 12b09b9..290b2f5 100644
--- a/chrome/browser/ui/views/app_list/win/app_list_service_win.h
+++ b/chrome/browser/ui/views/app_list/win/app_list_service_win.h
@@ -24,8 +24,6 @@ class AppListServiceWin : public AppListServiceViews {
virtual void HandleFirstRun() OVERRIDE;
virtual void Init(Profile* initial_profile) OVERRIDE;
virtual void ShowForProfile(Profile* requested_profile) OVERRIDE;
-
- // AppListServiceImpl overrides:
virtual void CreateShortcut() OVERRIDE;
private:
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index e594589..67d3fbe 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -44,9 +44,6 @@ using content::BrowserThread;
namespace {
-typedef base::Callback<void(const web_app::ShortcutInfo&,
- const extensions::FileHandlersInfo&)> InfoCallback;
-
#if defined(OS_MACOSX)
const int kDesiredSizes[] = {16, 32, 128, 256, 512};
const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
@@ -107,7 +104,7 @@ void UpdateAllShortcutsForShortcutInfo(
void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
extensions::FileHandlersInfo file_handlers_info,
- InfoCallback callback,
+ web_app::InfoCallback callback,
const gfx::ImageFamily& image_family) {
// If the image failed to load (e.g. if the resource being loaded was empty)
// use the standard application icon.
@@ -130,6 +127,27 @@ void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
callback.Run(shortcut_info, file_handlers_info);
}
+void IgnoreFileHandlersInfo(
+ const web_app::ShortcutInfoCallback& shortcut_info_callback,
+ const web_app::ShortcutInfo& shortcut_info,
+ const extensions::FileHandlersInfo& file_handlers_info) {
+ shortcut_info_callback.Run(shortcut_info);
+}
+
+} // namespace
+
+namespace web_app {
+
+// The following string is used to build the directory name for
+// shortcuts to chrome applications (the kind which are installed
+// from a CRX). Application shortcuts to URLs use the {host}_{path}
+// for the name of this directory. Hosts can't include an underscore.
+// By starting this string with an underscore, we ensure that there
+// are no naming conflicts.
+static const char kCrxAppPrefix[] = "_crx_";
+
+namespace internals {
+
void GetInfoForApp(const extensions::Extension* extension,
Profile* profile,
const InfoCallback& callback) {
@@ -185,27 +203,6 @@ void GetInfoForApp(const extensions::Extension* extension,
base::Bind(&OnImageLoaded, shortcut_info, file_handlers_info, callback));
}
-void IgnoreFileHandlersInfo(
- const web_app::ShortcutInfoCallback& shortcut_info_callback,
- const web_app::ShortcutInfo& shortcut_info,
- const extensions::FileHandlersInfo& file_handlers_info) {
- shortcut_info_callback.Run(shortcut_info);
-}
-
-} // namespace
-
-namespace web_app {
-
-// The following string is used to build the directory name for
-// shortcuts to chrome applications (the kind which are installed
-// from a CRX). Application shortcuts to URLs use the {host}_{path}
-// for the name of this directory. Hosts can't include an underscore.
-// By starting this string with an underscore, we ensure that there
-// are no naming conflicts.
-static const char* kCrxAppPrefix = "_crx_";
-
-namespace internals {
-
base::FilePath GetSanitizedFileName(const base::string16& name) {
#if defined(OS_WIN)
base::string16 file_name = name;
@@ -286,9 +283,8 @@ ShortcutInfo ShortcutInfoForExtensionAndProfile(
void UpdateShortcutInfoAndIconForApp(const extensions::Extension* extension,
Profile* profile,
const ShortcutInfoCallback& callback) {
- GetInfoForApp(extension,
- profile,
- base::Bind(&IgnoreFileHandlersInfo, callback));
+ web_app::internals::GetInfoForApp(
+ extension, profile, base::Bind(&IgnoreFileHandlersInfo, callback));
}
bool ShouldCreateShortcutFor(Profile* profile,
@@ -383,9 +379,8 @@ void CreateShortcuts(ShortcutCreationReason reason,
if (!ShouldCreateShortcutFor(profile, app))
return;
- GetInfoForApp(app,
- profile,
- base::Bind(&CreateShortcutsWithInfo, reason, locations));
+ internals::GetInfoForApp(
+ app, profile, base::Bind(&CreateShortcutsWithInfo, reason, locations));
}
void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
@@ -405,9 +400,10 @@ void UpdateAllShortcuts(const base::string16& old_app_title,
const extensions::Extension* app) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GetInfoForApp(app,
- profile,
- base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
+ internals::GetInfoForApp(
+ app,
+ profile,
+ base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
}
bool IsValidUrl(const GURL& url) {
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 79487681..c4f5eb2 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -96,6 +96,11 @@ enum ShortcutCreationReason {
SHORTCUT_CREATION_AUTOMATED,
};
+// Called by GetInfoForApp after fetching the ShortcutInfo and FileHandlersInfo.
+typedef base::Callback<void(const ShortcutInfo&,
+ const extensions::FileHandlersInfo&)> InfoCallback;
+
+// Called by UpdateShortcutInfoAndIconForApp after loading the icon.
typedef base::Callback<void(const ShortcutInfo&)> ShortcutInfoCallback;
// Extracts shortcut info of the given WebContents.
@@ -197,6 +202,11 @@ std::string GetWMClassFromAppName(std::string app_name);
namespace internals {
+// Loads relevant info structs for the app and calls |callback|.
+void GetInfoForApp(const extensions::Extension* extension,
+ Profile* profile,
+ const InfoCallback& callback);
+
#if defined(OS_WIN)
// Returns the Windows user-level shortcut paths that are specified in
// |creation_locations|.
diff --git a/chrome/browser/web_applications/web_app_mac.h b/chrome/browser/web_applications/web_app_mac.h
index a0a8b20..7c2ff41 100644
--- a/chrome/browser/web_applications/web_app_mac.h
+++ b/chrome/browser/web_applications/web_app_mac.h
@@ -14,6 +14,10 @@
#include "chrome/browser/web_applications/web_app.h"
#include "extensions/common/manifest_handlers/file_handler_info.h"
+namespace base {
+class CommandLine;
+}
+
// Whether to enable update and launch of app shims in tests. (Normally shims
// are never created or launched in tests). Note that update only creates
// internal shim bundles, i.e. it does not create new shims in ~/Applications.
@@ -28,6 +32,9 @@ base::FilePath GetAppInstallPath(const ShortcutInfo& shortcut_info);
// If necessary, launch the shortcut for an app.
void MaybeLaunchShortcut(const ShortcutInfo& shortcut_info);
+// Rebuild the shortcut and relaunch it.
+bool MaybeRebuildShortcut(const base::CommandLine& command_line);
+
// Creates a shortcut for a web application. The shortcut is a stub app
// that simply loads the browser framework and runs the given app.
class WebAppShortcutCreator {
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index b46170c..02f3f0d 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -20,14 +20,17 @@
#include "base/process/process_handle.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
#import "chrome/browser/mac/dock.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/ui/app_list/app_list_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -214,8 +217,8 @@ bool HasSameUserDataDir(const base::FilePath& bundle_path) {
true /* case_sensitive */);
}
-void LaunchShimOnFileThread(
- const web_app::ShortcutInfo& shortcut_info) {
+void LaunchShimOnFileThread(const web_app::ShortcutInfo& shortcut_info,
+ bool launched_after_rebuild) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info);
@@ -236,6 +239,8 @@ void LaunchShimOnFileThread(
command_line.AppendSwitchASCII(
app_mode::kLaunchedByChromeProcessId,
base::IntToString(base::GetCurrentProcId()));
+ if (launched_after_rebuild)
+ command_line.AppendSwitch(app_mode::kLaunchedAfterRebuild);
// Launch without activating (kLSLaunchDontSwitch).
base::mac::OpenApplicationWithPath(
shim_path, command_line, kLSLaunchDefaults | kLSLaunchDontSwitch, NULL);
@@ -246,6 +251,53 @@ base::FilePath GetAppLoaderPath() {
base::mac::NSToCFCast(@"app_mode_loader.app"));
}
+void UpdateAndLaunchShimOnFileThread(
+ const web_app::ShortcutInfo& shortcut_info,
+ const extensions::FileHandlersInfo& file_handlers_info) {
+ base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
+ shortcut_info.profile_path, shortcut_info.extension_id, GURL());
+ web_app::internals::UpdatePlatformShortcuts(
+ shortcut_data_dir, base::string16(), shortcut_info, file_handlers_info);
+ LaunchShimOnFileThread(shortcut_info, true);
+}
+
+void UpdateAndLaunchShim(
+ const web_app::ShortcutInfo& shortcut_info,
+ const extensions::FileHandlersInfo& file_handlers_info) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &UpdateAndLaunchShimOnFileThread, shortcut_info, file_handlers_info));
+}
+
+void RebuildAppAndLaunch(const web_app::ShortcutInfo& shortcut_info) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (shortcut_info.extension_id == app_mode::kAppListModeId) {
+ AppListService* app_list_service =
+ AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE);
+ app_list_service->CreateShortcut();
+ app_list_service->Show();
+ return;
+ }
+
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile =
+ profile_manager->GetProfileByPath(shortcut_info.profile_path);
+ if (!profile || !profile_manager->IsValidProfile(profile))
+ return;
+
+ extensions::ExtensionRegistry* registry =
+ extensions::ExtensionRegistry::Get(profile);
+ const extensions::Extension* extension = registry->GetExtensionById(
+ shortcut_info.extension_id, extensions::ExtensionRegistry::ENABLED);
+ if (!extension || !extension->is_platform_app())
+ return;
+
+ web_app::internals::GetInfoForApp(
+ extension, profile, base::Bind(&UpdateAndLaunchShim));
+}
+
base::FilePath GetLocalizableAppShortcutsSubdirName() {
static const char kChromiumAppDirName[] = "Chromium Apps.localized";
static const char kChromeAppDirName[] = "Chrome Apps.localized";
@@ -875,8 +927,22 @@ void MaybeLaunchShortcut(const ShortcutInfo& shortcut_info) {
}
content::BrowserThread::PostTask(
- content::BrowserThread::FILE, FROM_HERE,
- base::Bind(&LaunchShimOnFileThread, shortcut_info));
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&LaunchShimOnFileThread, shortcut_info, false));
+}
+
+bool MaybeRebuildShortcut(const CommandLine& command_line) {
+ if (!command_line.HasSwitch(app_mode::kAppShimError))
+ return false;
+
+ base::PostTaskAndReplyWithResult(
+ content::BrowserThread::GetBlockingPool(),
+ FROM_HERE,
+ base::Bind(&BuildShortcutInfoFromBundle,
+ command_line.GetSwitchValuePath(app_mode::kAppShimError)),
+ base::Bind(&RebuildAppAndLaunch));
+ return true;
}
// Called when the app's ShortcutInfo (with icon) is loaded when creating app
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 19609cc..6cecc30 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -286,7 +286,10 @@
'target_name': 'app_mode_app',
'type': 'executable',
'mac_bundle' : 1,
- 'variables': { 'enable_wexit_time_destructors': 1, },
+ 'variables': {
+ 'enable_wexit_time_destructors': 1,
+ 'mac_real_dsym': 1,
+ },
'product_name': 'app_mode_loader',
'dependencies': [
'app_mode_app_support',
diff --git a/chrome/common/mac/app_mode_chrome_locator.h b/chrome/common/mac/app_mode_chrome_locator.h
index 1b260d2..b608e9c 100644
--- a/chrome/common/mac/app_mode_chrome_locator.h
+++ b/chrome/common/mac/app_mode_chrome_locator.h
@@ -22,12 +22,14 @@ namespace app_mode {
bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle);
// Given the path to the Chrome bundle, read the following information:
+// |executable_path| - Path to the Chrome executable.
// |raw_version_str| - Chrome version.
// |version_path| - |chrome_bundle|/Contents/Versions/|raw_version_str|/
// |framework_shlib_path| - Path to the chrome framework's shared library (not
// the framework directory).
// Returns true if all information read succesfuly, false otherwise.
bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
+ base::FilePath* executable_path,
base::string16* raw_version_str,
base::FilePath* version_path,
base::FilePath* framework_shlib_path);
diff --git a/chrome/common/mac/app_mode_chrome_locator.mm b/chrome/common/mac/app_mode_chrome_locator.mm
index ac62380..3cd5302 100644
--- a/chrome/common/mac/app_mode_chrome_locator.mm
+++ b/chrome/common/mac/app_mode_chrome_locator.mm
@@ -25,6 +25,7 @@ bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle) {
}
bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
+ base::FilePath* executable_path,
base::string16* raw_version_str,
base::FilePath* version_path,
base::FilePath* framework_shlib_path) {
@@ -57,19 +58,25 @@ bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
NSString* cr_bundle_exe =
ObjCCast<NSString>(
[cr_bundle objectForInfoDictionaryKey:@"CFBundleExecutable"]);
+ // Essentially we want chrome::kFrameworkName which looks like
+ // "$PRODUCT_STRING Framework.framework". The library itself is at
+ // "$PRODUCT_STRING Framework.framework/$PRODUCT_STRING Framework". Note that
+ // $PRODUCT_STRING is not |cr_bundle_exe| because in Canary the framework is
+ // still called "Google Chrome Framework".
+ // However, we want the shims to be agnostic to distribution and operate based
+ // on the data in their plist, so encode the framework names here.
+ NSDictionary* framework_for_exe = @{
+ @"Chromium": @"Chromium",
+ @"Google Chrome": @"Google Chrome",
+ @"Google Chrome Canary": @"Google Chrome",
+ };
+ NSString* framework_name = [framework_for_exe objectForKey:cr_bundle_exe];
NSString* cr_framework_shlib_path =
[cr_versioned_path stringByAppendingPathComponent:
- base::SysUTF8ToNSString(chrome::kFrameworkName)];
- // chrome::kFrameworkName looks like "$PRODUCT_STRING Framework.framework".
- // The library itself is at
- // "$PRODUCT_STRING Framework.framework/$PRODUCT_STRING Framework", so we cut
- // off the .framework extension here and append it to the path.
- // It's important to build the path to the framework this way because
- // in Canary the framework is still called "Google Chrome Framework".
+ [framework_name stringByAppendingString:@" Framework.framework"]];
cr_framework_shlib_path =
[cr_framework_shlib_path stringByAppendingPathComponent:
- [base::SysUTF8ToNSString(chrome::kFrameworkName)
- stringByDeletingPathExtension]];
+ [framework_name stringByAppendingString:@" Framework"]];
if (!cr_bundle_exe || !cr_framework_shlib_path)
return false;
@@ -82,6 +89,7 @@ bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
return false;
// Everything OK, copy output parameters.
+ *executable_path = base::mac::NSStringToFilePath([cr_bundle executablePath]);
*raw_version_str = base::SysNSStringToUTF16(cr_version);
*version_path = base::mac::NSStringToFilePath(cr_versioned_path);
*framework_shlib_path =
diff --git a/chrome/common/mac/app_mode_chrome_locator_unittest.mm b/chrome/common/mac/app_mode_chrome_locator_unittest.mm
index 50e98bf..ecaed7d 100644
--- a/chrome/common/mac/app_mode_chrome_locator_unittest.mm
+++ b/chrome/common/mac/app_mode_chrome_locator_unittest.mm
@@ -43,11 +43,12 @@ TEST(ChromeLocatorTest, GetNonExistentBundleInfo) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath executable_path;
base::string16 raw_version;
base::FilePath version_path;
base::FilePath framework_path;
EXPECT_FALSE(app_mode::GetChromeBundleInfo(temp_dir.path(),
- &raw_version, &version_path, &framework_path));
+ &executable_path, &raw_version, &version_path, &framework_path));
}
TEST(ChromeLocatorTest, GetChromeBundleInfo) {
@@ -57,11 +58,13 @@ TEST(ChromeLocatorTest, GetChromeBundleInfo) {
GetChromeBundlePath(&chrome_bundle_path);
ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
+ base::FilePath executable_path;
base::string16 raw_version;
base::FilePath version_path;
base::FilePath framework_path;
EXPECT_TRUE(GetChromeBundleInfo(chrome_bundle_path,
- &raw_version, &version_path, &framework_path));
+ &executable_path, &raw_version, &version_path, &framework_path));
+ EXPECT_TRUE(base::PathExists(executable_path));
EXPECT_GT(raw_version.size(), 0U);
EXPECT_TRUE(base::DirectoryExists(version_path));
EXPECT_TRUE(base::PathExists(framework_path));
diff --git a/chrome/common/mac/app_mode_common.h b/chrome/common/mac/app_mode_common.h
index 4d686da..670b883 100644
--- a/chrome/common/mac/app_mode_common.h
+++ b/chrome/common/mac/app_mode_common.h
@@ -41,6 +41,10 @@ extern const char kLaunchedByChromeProcessId[];
// launch Chrome.
extern const char kLaunchedForTest[];
+// Indicates to the shim that this Chrome has rebuilt it once already, i.e. if
+// it fails to launch again, don't trigger another rebuild.
+extern const char kLaunchedAfterRebuild[];
+
// Path to an app shim bundle. Indicates to Chrome that this shim attempted to
// launch but failed.
extern const char kAppShimError[];
@@ -98,7 +102,7 @@ extern NSString* const kShortcutBrowserBundleIDPlaceholder;
// Current major/minor version numbers of |ChromeAppModeInfo| (defined below).
const unsigned kCurrentChromeAppModeInfoMajorVersion = 1;
-const unsigned kCurrentChromeAppModeInfoMinorVersion = 1;
+const unsigned kCurrentChromeAppModeInfoMinorVersion = 2;
// The structure used to pass information from the app mode loader to the
// (browser) framework. This is versioned using major and minor version numbers,
diff --git a/chrome/common/mac/app_mode_common.mm b/chrome/common/mac/app_mode_common.mm
index 9996090..bb63ed4 100644
--- a/chrome/common/mac/app_mode_common.mm
+++ b/chrome/common/mac/app_mode_common.mm
@@ -15,6 +15,7 @@ const char kAppListModeId[] = "app_list";
const char kLaunchedByChromeProcessId[] = "launched-by-chrome-process-id";
const char kLaunchedForTest[] = "launched-for-test";
+const char kLaunchedAfterRebuild[] = "launched-after-rebuild";
const char kAppShimError[] = "app-shim-error";