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

Side by Side Diff: chrome/app/app_mode_loader_mac.mm

Issue 265163006: [Mac] Rebuild app shims when they fail to dyload Chrome Framework. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add test. Rebase on http://crrev.com/316493002. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // On Mac, shortcuts can't have command-line arguments. Instead, produce small 5 // On Mac, shortcuts can't have command-line arguments. Instead, produce small
6 // app bundles which locate the Chromium framework and load it, passing the 6 // app bundles which locate the Chromium framework and load it, passing the
7 // appropriate data. This is the code for such an app bundle. It should be kept 7 // appropriate data. This is the code for such an app bundle. It should be kept
8 // minimal and do as little work as possible (with as much work done on 8 // minimal and do as little work as possible (with as much work done on
9 // framework side as possible). 9 // framework side as possible).
10 10
11 #include <dlfcn.h> 11 #include <dlfcn.h>
12 12
13 #include <CoreFoundation/CoreFoundation.h> 13 #include <CoreFoundation/CoreFoundation.h>
14 #import <Foundation/Foundation.h> 14 #import <Foundation/Foundation.h>
15 15
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/files/file_path.h" 18 #include "base/files/file_path.h"
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/mac/foundation_util.h" 20 #include "base/mac/foundation_util.h"
21 #include "base/mac/launch_services_util.h" 21 #include "base/mac/launch_services_util.h"
22 #include "base/mac/scoped_nsautorelease_pool.h" 22 #include "base/mac/scoped_nsautorelease_pool.h"
23 #include "base/process/launch.h"
23 #include "base/strings/sys_string_conversions.h" 24 #include "base/strings/sys_string_conversions.h"
25 #include "chrome/common/chrome_switches.h"
24 #import "chrome/common/mac/app_mode_chrome_locator.h" 26 #import "chrome/common/mac/app_mode_chrome_locator.h"
25 #include "chrome/common/mac/app_mode_common.h" 27 #include "chrome/common/mac/app_mode_common.h"
26 28
27 namespace { 29 namespace {
28 30
29 typedef int (*StartFun)(const app_mode::ChromeAppModeInfo*); 31 typedef int (*StartFun)(const app_mode::ChromeAppModeInfo*);
30 32
31 int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) { 33 int LoadFrameworkAndStart(app_mode::ChromeAppModeInfo* info) {
32 using base::SysNSStringToUTF8; 34 using base::SysNSStringToUTF8;
33 using base::SysNSStringToUTF16; 35 using base::SysNSStringToUTF16;
(...skipping 26 matching lines...) Expand all
60 if (!found_bundle) { 62 if (!found_bundle) {
61 // If no such bundle path exists, try to search by bundle ID. 63 // If no such bundle path exists, try to search by bundle ID.
62 if (!app_mode::FindBundleById(cr_bundle_id, &cr_bundle_path)) { 64 if (!app_mode::FindBundleById(cr_bundle_id, &cr_bundle_path)) {
63 // TODO(jeremy): Display UI to allow user to manually locate the Chrome 65 // TODO(jeremy): Display UI to allow user to manually locate the Chrome
64 // bundle. 66 // bundle.
65 LOG(FATAL) << "Failed to locate bundle by identifier"; 67 LOG(FATAL) << "Failed to locate bundle by identifier";
66 } 68 }
67 } 69 }
68 70
69 // ** 2: Read information from the Chrome bundle. 71 // ** 2: Read information from the Chrome bundle.
72 base::FilePath executable_path;
70 base::string16 raw_version_str; 73 base::string16 raw_version_str;
71 base::FilePath version_path; 74 base::FilePath version_path;
72 base::FilePath framework_shlib_path; 75 base::FilePath framework_shlib_path;
73 if (!app_mode::GetChromeBundleInfo(cr_bundle_path, &raw_version_str, 76 if (!app_mode::GetChromeBundleInfo(cr_bundle_path,
74 &version_path, &framework_shlib_path)) { 77 &executable_path,
78 &raw_version_str,
79 &version_path,
80 &framework_shlib_path)) {
75 LOG(FATAL) << "Couldn't ready Chrome bundle info"; 81 LOG(FATAL) << "Couldn't ready Chrome bundle info";
76 } 82 }
77 base::FilePath app_mode_bundle_path = 83 base::FilePath app_mode_bundle_path =
78 base::mac::NSStringToFilePath([app_bundle bundlePath]); 84 base::mac::NSStringToFilePath([app_bundle bundlePath]);
79 85
80 // ** 3: Fill in ChromeAppModeInfo. 86 // ** 3: Fill in ChromeAppModeInfo.
81 info->chrome_outer_bundle_path = cr_bundle_path; 87 info->chrome_outer_bundle_path = cr_bundle_path;
82 info->chrome_versioned_path = version_path; 88 info->chrome_versioned_path = version_path;
83 info->app_mode_bundle_path = app_mode_bundle_path; 89 info->app_mode_bundle_path = app_mode_bundle_path;
84 90
(...skipping 23 matching lines...) Expand all
108 void* cr_dylib = dlopen(framework_shlib_path.value().c_str(), RTLD_LAZY); 114 void* cr_dylib = dlopen(framework_shlib_path.value().c_str(), RTLD_LAZY);
109 if (cr_dylib) { 115 if (cr_dylib) {
110 // Find the entry point. 116 // Find the entry point.
111 ChromeAppModeStart = (StartFun)dlsym(cr_dylib, "ChromeAppModeStart"); 117 ChromeAppModeStart = (StartFun)dlsym(cr_dylib, "ChromeAppModeStart");
112 if (!ChromeAppModeStart) 118 if (!ChromeAppModeStart)
113 LOG(ERROR) << "Couldn't get entry point: " << dlerror(); 119 LOG(ERROR) << "Couldn't get entry point: " << dlerror();
114 } else { 120 } else {
115 LOG(ERROR) << "Couldn't load framework: " << dlerror(); 121 LOG(ERROR) << "Couldn't load framework: " << dlerror();
116 } 122 }
117 123
118 if (ChromeAppModeStart) { 124 if (ChromeAppModeStart)
119 return ChromeAppModeStart(info); 125 return ChromeAppModeStart(info);
126
127 LOG(ERROR) << "Loading Chrome failed, launching Chrome with command line";
128 CommandLine command_line(executable_path);
129 // The user_data_dir from the plist is actually the app data dir.
130 command_line.AppendSwitchPath(
131 switches::kUserDataDir,
132 info->user_data_dir.DirName().DirName().DirName());
133 if (CommandLine::ForCurrentProcess()->HasSwitch(
134 app_mode::kLaunchedByChromeProcessId) ||
135 info->app_mode_id == app_mode::kAppListModeId) {
136 // Pass --app-shim-error to have Chrome rebuild this shim.
137 // If Chrome has rebuilt this shim once already, then rebuilding doesn't fix
138 // the problem, so don't try again.
139 if (!CommandLine::ForCurrentProcess()->HasSwitch(
140 app_mode::kLaunchedAfterRebuild)) {
141 command_line.AppendSwitchPath(app_mode::kAppShimError,
142 app_mode_bundle_path);
143 }
120 } else { 144 } else {
121 LOG(ERROR) << "Loading Chrome failed, launching with command line."; 145 // If the shim was launched directly (instead of by Chrome), first ask
122 // Launch Chrome instead and have it update this app_mode_loader bundle. 146 // Chrome to launch the app. Chrome will launch the shim again, the same
123 CommandLine command_line(CommandLine::NO_PROGRAM); 147 // error will occur and be handled above. This approach allows the app to be
124 command_line.AppendSwitchPath(app_mode::kAppShimError, 148 // started without blocking on fixing the shim and guarantees that the
125 app_mode_bundle_path); 149 // profile is loaded when Chrome receives --app-shim-error.
126 if (!base::mac::OpenApplicationWithPath( 150 command_line.AppendSwitchPath(switches::kProfileDirectory,
127 cr_bundle_path, command_line, kLSLaunchDefaults, NULL)) { 151 info->profile_dir);
128 LOG(ERROR) << "Could not launch Chrome from: " << cr_bundle_path.value(); 152 command_line.AppendSwitchASCII(switches::kAppId, info->app_mode_id);
129 return 1; 153 }
130 } 154 // Launch the executable directly since base::mac::OpenApplicationWithPath
155 // uses LSOpenApplication which doesn't pass command line arguments if the
156 // application is already running.
157 if (!base::LaunchProcess(command_line, base::LaunchOptions(), NULL)) {
158 LOG(ERROR) << "Could not launch Chrome: "
159 << command_line.GetCommandLineString();
160 return 1;
161 }
131 162
132 return 0; 163 return 0;
133 }
134 } 164 }
135 165
136 } // namespace 166 } // namespace
137 167
138 __attribute__((visibility("default"))) 168 __attribute__((visibility("default")))
139 int main(int argc, char** argv) { 169 int main(int argc, char** argv) {
170 CommandLine::Init(argc, argv);
140 app_mode::ChromeAppModeInfo info; 171 app_mode::ChromeAppModeInfo info;
141 172
142 // Hard coded info parameters. 173 // Hard coded info parameters.
143 info.major_version = app_mode::kCurrentChromeAppModeInfoMajorVersion; 174 info.major_version = app_mode::kCurrentChromeAppModeInfoMajorVersion;
144 info.minor_version = app_mode::kCurrentChromeAppModeInfoMinorVersion; 175 info.minor_version = app_mode::kCurrentChromeAppModeInfoMinorVersion;
145 info.argc = argc; 176 info.argc = argc;
146 info.argv = argv; 177 info.argv = argv;
147 178
148 // Exit instead of returning to avoid the the removal of |main()| from stack 179 // Exit instead of returning to avoid the the removal of |main()| from stack
149 // backtraces under tail call optimization. 180 // backtraces under tail call optimization.
150 exit(LoadFrameworkAndStart(&info)); 181 exit(LoadFrameworkAndStart(&info));
151 } 182 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698