OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/compiler_specific.h" | |
10 #include "base/environment.h" | |
11 #include "base/event_recorder.h" | |
12 #include "base/lazy_instance.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/metrics/histogram.h" | |
15 #include "base/path_service.h" | |
16 #include "base/string_number_conversions.h" | |
17 #include "base/string_split.h" | |
18 #include "base/threading/thread_restrictions.h" | |
19 #include "base/utf_string_conversions.h" | |
20 #include "chrome/browser/auto_launch_trial.h" | |
21 #include "chrome/browser/browser_process.h" | |
22 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" | |
23 #include "chrome/browser/defaults.h" | |
24 #include "chrome/browser/extensions/extension_creator.h" | |
25 #include "chrome/browser/extensions/extension_service.h" | |
26 #include "chrome/browser/extensions/pack_extension_job.h" | |
27 #include "chrome/browser/first_run/first_run.h" | |
28 #include "chrome/browser/net/predictor.h" | |
29 #include "chrome/browser/net/url_fixer_upper.h" | |
30 #include "chrome/browser/notifications/desktop_notification_service.h" | |
31 #include "chrome/browser/prefs/incognito_mode_prefs.h" | |
32 #include "chrome/browser/prefs/pref_service.h" | |
33 #include "chrome/browser/prefs/session_startup_pref.h" | |
34 #include "chrome/browser/profiles/profile.h" | |
35 #include "chrome/browser/profiles/profile_io_data.h" | |
36 #include "chrome/browser/protector/protected_prefs_watcher.h" | |
37 #include "chrome/browser/protector/protector_service.h" | |
38 #include "chrome/browser/protector/protector_service_factory.h" | |
39 #include "chrome/browser/protector/protector_utils.h" | |
40 #include "chrome/browser/sessions/session_restore.h" | |
41 #include "chrome/browser/sessions/session_service.h" | |
42 #include "chrome/browser/sessions/session_service_factory.h" | |
43 #include "chrome/browser/shell_integration.h" | |
44 #include "chrome/browser/tabs/pinned_tab_codec.h" | |
45 #include "chrome/browser/tabs/tab_strip_model.h" | |
46 #include "chrome/browser/ui/browser_list.h" | |
47 #include "chrome/browser/ui/browser_navigator.h" | |
48 #include "chrome/browser/ui/browser_window.h" | |
49 #include "chrome/browser/ui/startup/autolaunch_prompt.h" | |
50 #include "chrome/browser/ui/startup/bad_flags_prompt.h" | |
51 #include "chrome/browser/ui/startup/default_browser_prompt.h" | |
52 #include "chrome/browser/ui/startup/obsolete_os_prompt.h" | |
53 #include "chrome/browser/ui/startup/session_crashed_prompt.h" | |
54 #include "chrome/browser/ui/startup/startup_browser_creator.h" | |
55 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
56 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" | |
57 #include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h" | |
58 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" | |
59 #include "chrome/common/chrome_constants.h" | |
60 #include "chrome/common/chrome_notification_types.h" | |
61 #include "chrome/common/chrome_paths.h" | |
62 #include "chrome/common/chrome_result_codes.h" | |
63 #include "chrome/common/chrome_switches.h" | |
64 #include "chrome/common/chrome_version_info.h" | |
65 #include "chrome/common/extensions/extension_constants.h" | |
66 #include "chrome/common/pref_names.h" | |
67 #include "chrome/common/url_constants.h" | |
68 #include "chrome/installer/util/browser_distribution.h" | |
69 #include "content/public/browser/child_process_security_policy.h" | |
70 #include "content/public/browser/web_contents.h" | |
71 #include "content/public/browser/web_contents_view.h" | |
72 #include "grit/locale_settings.h" | |
73 #include "ui/base/l10n/l10n_util.h" | |
74 #include "ui/base/resource/resource_bundle.h" | |
75 | |
76 #if defined(OS_MACOSX) | |
77 #include "base/mac/mac_util.h" | |
78 #include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h" | |
79 #endif | |
80 | |
81 #if defined(TOOLKIT_GTK) | |
82 #include "chrome/browser/ui/gtk/gtk_util.h" | |
83 #endif | |
84 | |
85 #if defined(OS_WIN) | |
86 #include "base/win/windows_version.h" | |
87 #endif | |
88 | |
89 using content::ChildProcessSecurityPolicy; | |
90 using content::WebContents; | |
91 using protector::ProtectedPrefsWatcher; | |
92 using protector::ProtectorService; | |
93 using protector::ProtectorServiceFactory; | |
94 | |
95 extern bool in_synchronous_profile_launch; | |
96 | |
97 namespace { | |
98 | |
99 // Utility functions ---------------------------------------------------------- | |
100 | |
101 enum LaunchMode { | |
102 LM_TO_BE_DECIDED = 0, // Possibly direct launch or via a shortcut. | |
103 LM_AS_WEBAPP, // Launched as a installed web application. | |
104 LM_WITH_URLS, // Launched with urls in the cmd line. | |
105 LM_SHORTCUT_NONE, // Not launched from a shortcut. | |
106 LM_SHORTCUT_NONAME, // Launched from shortcut but no name available. | |
107 LM_SHORTCUT_UNKNOWN, // Launched from user-defined shortcut. | |
108 LM_SHORTCUT_QUICKLAUNCH, // Launched from the quick launch bar. | |
109 LM_SHORTCUT_DESKTOP, // Launched from a desktop shortcut. | |
110 LM_SHORTCUT_TASKBAR, // Launched from the taskbar. | |
111 LM_LINUX_MAC_BEOS // Other OS buckets start here. | |
112 }; | |
113 | |
114 #if defined(OS_WIN) | |
115 // Undocumented flag in the startup info structure tells us what shortcut was | |
116 // used to launch the browser. See http://www.catch22.net/tuts/undoc01 for | |
117 // more information. Confirmed to work on XP, Vista and Win7. | |
118 LaunchMode GetLaunchShortcutKind() { | |
119 STARTUPINFOW si = { sizeof(si) }; | |
120 GetStartupInfoW(&si); | |
121 if (si.dwFlags & 0x800) { | |
122 if (!si.lpTitle) | |
123 return LM_SHORTCUT_NONAME; | |
124 string16 shortcut(si.lpTitle); | |
125 // The windows quick launch path is not localized. | |
126 if (shortcut.find(L"\\Quick Launch\\") != string16::npos) { | |
127 if (base::win::GetVersion() >= base::win::VERSION_WIN7) | |
128 return LM_SHORTCUT_TASKBAR; | |
129 else | |
130 return LM_SHORTCUT_QUICKLAUNCH; | |
131 } | |
132 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
133 std::string appdata_path; | |
134 env->GetVar("USERPROFILE", &appdata_path); | |
135 if (!appdata_path.empty() && | |
136 shortcut.find(ASCIIToWide(appdata_path)) != std::wstring::npos) | |
137 return LM_SHORTCUT_DESKTOP; | |
138 return LM_SHORTCUT_UNKNOWN; | |
139 } | |
140 return LM_SHORTCUT_NONE; | |
141 } | |
142 #else | |
143 // TODO(cpu): Port to other platforms. | |
144 LaunchMode GetLaunchShortcutKind() { | |
145 return LM_LINUX_MAC_BEOS; | |
146 } | |
147 #endif | |
148 | |
149 // Log in a histogram the frequency of launching by the different methods. See | |
150 // LaunchMode enum for the actual values of the buckets. | |
151 void RecordLaunchModeHistogram(LaunchMode mode) { | |
152 int bucket = (mode == LM_TO_BE_DECIDED) ? GetLaunchShortcutKind() : mode; | |
153 UMA_HISTOGRAM_COUNTS_100("Launch.Modes", bucket); | |
154 } | |
155 | |
156 GURL GetWelcomePageURL() { | |
157 std::string welcome_url = l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL); | |
158 return GURL(welcome_url); | |
159 } | |
160 | |
161 void UrlsToTabs(const std::vector<GURL>& urls, StartupTabs* tabs) { | |
162 for (size_t i = 0; i < urls.size(); ++i) { | |
163 StartupTab tab; | |
164 tab.is_pinned = false; | |
165 tab.url = urls[i]; | |
166 tabs->push_back(tab); | |
167 } | |
168 } | |
169 | |
170 // Return true if the command line option --app-id is used. Set | |
171 // |out_extension| to the app to open, and |out_launch_container| | |
172 // to the type of window into which the app should be open. | |
173 bool GetAppLaunchContainer( | |
174 Profile* profile, | |
175 const std::string& app_id, | |
176 const Extension** out_extension, | |
177 extension_misc::LaunchContainer* out_launch_container) { | |
178 | |
179 ExtensionService* extensions_service = profile->GetExtensionService(); | |
180 const Extension* extension = | |
181 extensions_service->GetExtensionById(app_id, false); | |
182 | |
183 // The extension with id |app_id| may have been uninstalled. | |
184 if (!extension) | |
185 return false; | |
186 | |
187 // Look at preferences to find the right launch container. If no | |
188 // preference is set, launch as a window. | |
189 extension_misc::LaunchContainer launch_container = | |
190 extensions_service->extension_prefs()->GetLaunchContainer( | |
191 extension, ExtensionPrefs::LAUNCH_WINDOW); | |
192 | |
193 *out_extension = extension; | |
194 *out_launch_container = launch_container; | |
195 return true; | |
196 } | |
197 | |
198 void RecordCmdLineAppHistogram() { | |
199 AppLauncherHandler::RecordAppLaunchType( | |
200 extension_misc::APP_LAUNCH_CMD_LINE_APP); | |
201 } | |
202 | |
203 void RecordAppLaunches(Profile* profile, | |
204 const std::vector<GURL>& cmd_line_urls, | |
205 StartupTabs& autolaunch_tabs) { | |
206 ExtensionService* extension_service = profile->GetExtensionService(); | |
207 DCHECK(extension_service); | |
208 for (size_t i = 0; i < cmd_line_urls.size(); ++i) { | |
209 if (extension_service->IsInstalledApp(cmd_line_urls.at(i))) { | |
210 AppLauncherHandler::RecordAppLaunchType( | |
211 extension_misc::APP_LAUNCH_CMD_LINE_URL); | |
212 } | |
213 } | |
214 for (size_t i = 0; i < autolaunch_tabs.size(); ++i) { | |
215 if (extension_service->IsInstalledApp(autolaunch_tabs.at(i).url)) { | |
216 AppLauncherHandler::RecordAppLaunchType( | |
217 extension_misc::APP_LAUNCH_AUTOLAUNCH); | |
218 } | |
219 } | |
220 } | |
221 | |
222 } // namespace | |
223 | |
224 StartupBrowserCreatorImpl::StartupBrowserCreatorImpl( | |
225 const FilePath& cur_dir, | |
226 const CommandLine& command_line, | |
227 browser::startup::IsFirstRun is_first_run) | |
228 : cur_dir_(cur_dir), | |
229 command_line_(command_line), | |
230 profile_(NULL), | |
231 browser_creator_(NULL), | |
232 is_first_run_(is_first_run == browser::startup::IS_FIRST_RUN) { | |
233 } | |
234 | |
235 StartupBrowserCreatorImpl::StartupBrowserCreatorImpl( | |
236 const FilePath& cur_dir, | |
237 const CommandLine& command_line, | |
238 StartupBrowserCreator* browser_creator, | |
239 browser::startup::IsFirstRun is_first_run) | |
240 : cur_dir_(cur_dir), | |
241 command_line_(command_line), | |
242 profile_(NULL), | |
243 browser_creator_(browser_creator), | |
244 is_first_run_(is_first_run == browser::startup::IS_FIRST_RUN) { | |
245 } | |
246 | |
247 StartupBrowserCreatorImpl::~StartupBrowserCreatorImpl() { | |
248 } | |
249 | |
250 bool StartupBrowserCreatorImpl::Launch(Profile* profile, | |
251 const std::vector<GURL>& urls_to_open, | |
252 bool process_startup) { | |
253 DCHECK(profile); | |
254 profile_ = profile; | |
255 | |
256 if (command_line_.HasSwitch(switches::kDnsLogDetails)) | |
257 chrome_browser_net::EnablePredictorDetailedLog(true); | |
258 if (command_line_.HasSwitch(switches::kDnsPrefetchDisable) && | |
259 profile->GetNetworkPredictor()) { | |
260 profile->GetNetworkPredictor()->EnablePredictor(false); | |
261 } | |
262 | |
263 if (command_line_.HasSwitch(switches::kDumpHistogramsOnExit)) | |
264 base::StatisticsRecorder::set_dump_on_exit(true); | |
265 | |
266 if (command_line_.HasSwitch(switches::kRemoteDebuggingPort)) { | |
267 std::string port_str = | |
268 command_line_.GetSwitchValueASCII(switches::kRemoteDebuggingPort); | |
269 int64 port; | |
270 if (base::StringToInt64(port_str, &port) && port > 0 && port < 65535) { | |
271 std::string frontend_str; | |
272 if (command_line_.HasSwitch(switches::kRemoteDebuggingFrontend)) { | |
273 frontend_str = command_line_.GetSwitchValueASCII( | |
274 switches::kRemoteDebuggingFrontend); | |
275 } | |
276 g_browser_process->InitDevToolsHttpProtocolHandler( | |
277 profile, | |
278 "127.0.0.1", | |
279 static_cast<int>(port), | |
280 frontend_str); | |
281 } else { | |
282 DLOG(WARNING) << "Invalid http debugger port number " << port; | |
283 } | |
284 } | |
285 | |
286 // Open the required browser windows and tabs. First, see if | |
287 // we're being run as an application window. If so, the user | |
288 // opened an app shortcut. Don't restore tabs or open initial | |
289 // URLs in that case. The user should see the window as an app, | |
290 // not as chrome. | |
291 // Special case is when app switches are passed but we do want to restore | |
292 // session. In that case open app window + focus it after session is restored. | |
293 if (OpenApplicationWindow(profile) && !browser_defaults::kAppRestoreSession) { | |
294 RecordLaunchModeHistogram(LM_AS_WEBAPP); | |
295 } else { | |
296 Browser* browser_to_focus = NULL; | |
297 // In case of app mode + session restore we want to focus that app. | |
298 if (browser_defaults::kAppRestoreSession) | |
299 browser_to_focus = BrowserList::GetLastActive(); | |
300 | |
301 RecordLaunchModeHistogram(urls_to_open.empty()? | |
302 LM_TO_BE_DECIDED : LM_WITH_URLS); | |
303 | |
304 // Notify user if the Preferences backup is invalid or changes to settings | |
305 // affecting browser startup have been detected. | |
306 CheckPreferencesBackup(profile); | |
307 | |
308 ProcessLaunchURLs(process_startup, urls_to_open); | |
309 | |
310 // If this is an app launch, but we didn't open an app window, it may | |
311 // be an app tab. | |
312 OpenApplicationTab(profile); | |
313 | |
314 if (browser_to_focus) | |
315 browser_to_focus->GetSelectedWebContents()->GetView()->SetInitialFocus(); | |
316 | |
317 if (process_startup) { | |
318 if (browser_defaults::kOSSupportsOtherBrowsers && | |
319 !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) { | |
320 if (!browser::ShowAutolaunchPrompt(profile)) | |
321 browser::ShowDefaultBrowserPrompt(profile); | |
322 } | |
323 #if defined(OS_MACOSX) | |
324 // Check whether the auto-update system needs to be promoted from user | |
325 // to system. | |
326 KeystoneInfoBar::PromotionInfoBar(profile); | |
327 #endif | |
328 } | |
329 } | |
330 | |
331 #if defined(OS_WIN) | |
332 // Print the selected page if the command line switch exists. Note that the | |
333 // current selected tab would be the page which will be printed. | |
334 if (command_line_.HasSwitch(switches::kPrint)) { | |
335 Browser* browser = BrowserList::GetLastActive(); | |
336 browser->Print(); | |
337 } | |
338 #endif | |
339 | |
340 // If we're recording or playing back, startup the EventRecorder now | |
341 // unless otherwise specified. | |
342 if (!command_line_.HasSwitch(switches::kNoEvents)) { | |
343 FilePath script_path; | |
344 PathService::Get(chrome::FILE_RECORDED_SCRIPT, &script_path); | |
345 | |
346 bool record_mode = command_line_.HasSwitch(switches::kRecordMode); | |
347 bool playback_mode = command_line_.HasSwitch(switches::kPlaybackMode); | |
348 | |
349 if (record_mode && chrome::kRecordModeEnabled) | |
350 base::EventRecorder::current()->StartRecording(script_path); | |
351 if (playback_mode) | |
352 base::EventRecorder::current()->StartPlayback(script_path); | |
353 } | |
354 | |
355 #if defined(OS_WIN) | |
356 if (process_startup) | |
357 ShellIntegration::MigrateChromiumShortcuts(); | |
358 #endif // defined(OS_WIN) | |
359 | |
360 return true; | |
361 } | |
362 | |
363 bool StartupBrowserCreatorImpl::IsAppLaunch(std::string* app_url, | |
364 std::string* app_id) { | |
365 if (command_line_.HasSwitch(switches::kApp)) { | |
366 if (app_url) | |
367 *app_url = command_line_.GetSwitchValueASCII(switches::kApp); | |
368 return true; | |
369 } | |
370 if (command_line_.HasSwitch(switches::kAppId)) { | |
371 if (app_id) | |
372 *app_id = command_line_.GetSwitchValueASCII(switches::kAppId); | |
373 return true; | |
374 } | |
375 return false; | |
376 } | |
377 | |
378 bool StartupBrowserCreatorImpl::OpenApplicationTab(Profile* profile) { | |
379 std::string app_id; | |
380 // App shortcuts to URLs always open in an app window. Because this | |
381 // function will open an app that should be in a tab, there is no need | |
382 // to look at the app URL. OpenApplicationWindow() will open app url | |
383 // shortcuts. | |
384 if (!IsAppLaunch(NULL, &app_id) || app_id.empty()) | |
385 return false; | |
386 | |
387 extension_misc::LaunchContainer launch_container; | |
388 const Extension* extension; | |
389 if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) | |
390 return false; | |
391 | |
392 // If the user doesn't want to open a tab, fail. | |
393 if (launch_container != extension_misc::LAUNCH_TAB) | |
394 return false; | |
395 | |
396 RecordCmdLineAppHistogram(); | |
397 | |
398 WebContents* app_tab = Browser::OpenApplicationTab(profile, extension, GURL(), | |
399 NEW_FOREGROUND_TAB); | |
400 return (app_tab != NULL); | |
401 } | |
402 | |
403 bool StartupBrowserCreatorImpl::OpenApplicationWindow(Profile* profile) { | |
404 std::string url_string, app_id; | |
405 if (!IsAppLaunch(&url_string, &app_id)) | |
406 return false; | |
407 | |
408 // This can fail if the app_id is invalid. It can also fail if the | |
409 // extension is external, and has not yet been installed. | |
410 // TODO(skerner): Do something reasonable here. Pop up a warning panel? | |
411 // Open an URL to the gallery page of the extension id? | |
412 if (!app_id.empty()) { | |
413 extension_misc::LaunchContainer launch_container; | |
414 const Extension* extension; | |
415 if (!GetAppLaunchContainer(profile, app_id, &extension, &launch_container)) | |
416 return false; | |
417 | |
418 // TODO(skerner): Could pass in |extension| and |launch_container|, | |
419 // and avoid calling GetAppLaunchContainer() both here and in | |
420 // OpenApplicationTab(). | |
421 | |
422 if (launch_container == extension_misc::LAUNCH_TAB) | |
423 return false; | |
424 | |
425 RecordCmdLineAppHistogram(); | |
426 WebContents* tab_in_app_window = Browser::OpenApplication( | |
427 profile, extension, launch_container, GURL(), NEW_WINDOW); | |
428 // Platform apps fire off a launch event which may or may not open a window. | |
429 return (tab_in_app_window != NULL || extension->is_platform_app()); | |
430 } | |
431 | |
432 if (url_string.empty()) | |
433 return false; | |
434 | |
435 #if defined(OS_WIN) // Fix up Windows shortcuts. | |
436 ReplaceSubstringsAfterOffset(&url_string, 0, "\\x", "%"); | |
437 #endif | |
438 GURL url(url_string); | |
439 | |
440 // Restrict allowed URLs for --app switch. | |
441 if (!url.is_empty() && url.is_valid()) { | |
442 ChildProcessSecurityPolicy *policy = | |
443 ChildProcessSecurityPolicy::GetInstance(); | |
444 if (policy->IsWebSafeScheme(url.scheme()) || | |
445 url.SchemeIs(chrome::kFileScheme)) { | |
446 | |
447 if (profile->GetExtensionService()->IsInstalledApp(url)) { | |
448 RecordCmdLineAppHistogram(); | |
449 } else { | |
450 AppLauncherHandler::RecordAppLaunchType( | |
451 extension_misc::APP_LAUNCH_CMD_LINE_APP_LEGACY); | |
452 } | |
453 WebContents* app_tab = Browser::OpenAppShortcutWindow( | |
454 profile, | |
455 url, | |
456 true); // Update app info. | |
457 return (app_tab != NULL); | |
458 } | |
459 } | |
460 return false; | |
461 } | |
462 | |
463 void StartupBrowserCreatorImpl::ProcessLaunchURLs( | |
464 bool process_startup, | |
465 const std::vector<GURL>& urls_to_open) { | |
466 // If we're starting up in "background mode" (no open browser window) then | |
467 // don't open any browser windows, unless kAutoLaunchAtStartup is also | |
468 // specified. | |
469 if (process_startup && | |
470 command_line_.HasSwitch(switches::kNoStartupWindow) && | |
471 !command_line_.HasSwitch(switches::kAutoLaunchAtStartup)) { | |
472 return; | |
473 } | |
474 | |
475 if (process_startup && ProcessStartupURLs(urls_to_open)) { | |
476 // ProcessStartupURLs processed the urls, nothing else to do. | |
477 return; | |
478 } | |
479 | |
480 browser::startup::IsProcessStartup is_process_startup = process_startup ? | |
481 browser::startup::IS_PROCESS_STARTUP : | |
482 browser::startup::IS_NOT_PROCESS_STARTUP; | |
483 if (!process_startup) { | |
484 // Even if we're not starting a new process, this may conceptually be | |
485 // "startup" for the user and so should be handled in a similar way. Eg., | |
486 // Chrome may have been running in the background due to an app with a | |
487 // background page being installed, or running with only an app window | |
488 // displayed. | |
489 SessionService* service = SessionServiceFactory::GetForProfile(profile_); | |
490 if (service && service->ShouldNewWindowStartSession()) { | |
491 // Restore the last session if any. | |
492 if (!HasPendingUncleanExit(profile_) && | |
493 service->RestoreIfNecessary(urls_to_open)) { | |
494 return; | |
495 } | |
496 // Open user-specified URLs like pinned tabs and startup tabs. | |
497 Browser* browser = ProcessSpecifiedURLs(urls_to_open); | |
498 if (browser) { | |
499 AddInfoBarsIfNecessary(browser, is_process_startup); | |
500 return; | |
501 } | |
502 } | |
503 } | |
504 | |
505 // Session startup didn't occur, open the urls. | |
506 | |
507 Browser* browser = NULL; | |
508 std::vector<GURL> adjust_urls = urls_to_open; | |
509 if (adjust_urls.empty()) | |
510 AddStartupURLs(&adjust_urls); | |
511 else if (!command_line_.HasSwitch(switches::kOpenInNewWindow)) | |
512 browser = BrowserList::GetLastActiveWithProfile(profile_); | |
513 | |
514 // This will launch a browser; prevent session restore. | |
515 in_synchronous_profile_launch = true; | |
516 browser = OpenURLsInBrowser(browser, process_startup, adjust_urls); | |
517 in_synchronous_profile_launch = false; | |
518 AddInfoBarsIfNecessary(browser, is_process_startup); | |
519 } | |
520 | |
521 bool StartupBrowserCreatorImpl::ProcessStartupURLs( | |
522 const std::vector<GURL>& urls_to_open) { | |
523 SessionStartupPref pref = | |
524 StartupBrowserCreator::GetSessionStartupPref(command_line_, profile_); | |
525 | |
526 if (pref.type == SessionStartupPref::LAST) { | |
527 if (!profile_->DidLastSessionExitCleanly() && | |
528 !command_line_.HasSwitch(switches::kRestoreLastSession)) { | |
529 // The last session crashed. It's possible automatically loading the | |
530 // page will trigger another crash, locking the user out of chrome. | |
531 // To avoid this, don't restore on startup but instead show the crashed | |
532 // infobar. | |
533 return false; | |
534 } | |
535 | |
536 uint32 restore_behavior = SessionRestore::SYNCHRONOUS | | |
537 SessionRestore::ALWAYS_CREATE_TABBED_BROWSER; | |
538 #if defined(OS_MACOSX) | |
539 // On Mac, when restoring a session with no windows, suppress the creation | |
540 // of a new window in the case where the system is launching Chrome via a | |
541 // login item or Lion's resume feature. | |
542 if (base::mac::WasLaunchedAsLoginOrResumeItem()) { | |
543 restore_behavior = restore_behavior & | |
544 ~SessionRestore::ALWAYS_CREATE_TABBED_BROWSER; | |
545 } | |
546 #endif | |
547 | |
548 Browser* browser = SessionRestore::RestoreSession(profile_, | |
549 NULL, | |
550 restore_behavior, | |
551 urls_to_open); | |
552 AddInfoBarsIfNecessary(browser, browser::startup::IS_PROCESS_STARTUP); | |
553 return true; | |
554 } | |
555 | |
556 Browser* browser = ProcessSpecifiedURLs(urls_to_open); | |
557 if (!browser) | |
558 return false; | |
559 | |
560 AddInfoBarsIfNecessary(browser, browser::startup::IS_PROCESS_STARTUP); | |
561 return true; | |
562 } | |
563 | |
564 Browser* StartupBrowserCreatorImpl::ProcessSpecifiedURLs( | |
565 const std::vector<GURL>& urls_to_open) { | |
566 SessionStartupPref pref = | |
567 StartupBrowserCreator::GetSessionStartupPref(command_line_, profile_); | |
568 StartupTabs tabs; | |
569 // Pinned tabs should not be displayed when chrome is launched in incognito | |
570 // mode. Also, no pages should be opened automatically if the session | |
571 // crashed. Otherwise it might trigger another crash, locking the user out of | |
572 // chrome. The crash infobar is shown in this case. | |
573 if (!IncognitoModePrefs::ShouldLaunchIncognito(command_line_, | |
574 profile_->GetPrefs()) && | |
575 !HasPendingUncleanExit(profile_)) { | |
576 tabs = PinnedTabCodec::ReadPinnedTabs(profile_); | |
577 } | |
578 | |
579 RecordAppLaunches(profile_, urls_to_open, tabs); | |
580 | |
581 if (!urls_to_open.empty()) { | |
582 // If urls were specified on the command line, use them. | |
583 UrlsToTabs(urls_to_open, &tabs); | |
584 } else if (pref.type == SessionStartupPref::URLS && !pref.urls.empty() && | |
585 !HasPendingUncleanExit(profile_)) { | |
586 // Only use the set of urls specified in preferences if nothing was | |
587 // specified on the command line. Filter out any urls that are to be | |
588 // restored by virtue of having been previously pinned. | |
589 AddUniqueURLs(pref.urls, &tabs); | |
590 } else if (pref.type == SessionStartupPref::DEFAULT) { | |
591 std::vector<GURL> urls; | |
592 AddStartupURLs(&urls); | |
593 UrlsToTabs(urls, &tabs); | |
594 | |
595 } else if (pref.type == SessionStartupPref::HOMEPAGE) { | |
596 // If 'homepage' selected, either by the user or by a policy, we should | |
597 // have migrated them to another value. | |
598 NOTREACHED() << "SessionStartupPref has deprecated type HOMEPAGE"; | |
599 } | |
600 | |
601 if (tabs.empty()) | |
602 return NULL; | |
603 | |
604 Browser* browser = OpenTabsInBrowser(NULL, true, tabs); | |
605 return browser; | |
606 } | |
607 | |
608 void StartupBrowserCreatorImpl::AddUniqueURLs(const std::vector<GURL>& urls, | |
609 StartupTabs* tabs) { | |
610 size_t num_existing_tabs = tabs->size(); | |
611 for (size_t i = 0; i < urls.size(); ++i) { | |
612 bool in_tabs = false; | |
613 for (size_t j = 0; j < num_existing_tabs; ++j) { | |
614 if (urls[i] == (*tabs)[j].url) { | |
615 in_tabs = true; | |
616 break; | |
617 } | |
618 } | |
619 if (!in_tabs) { | |
620 StartupTab tab; | |
621 tab.is_pinned = false; | |
622 tab.url = urls[i]; | |
623 tabs->push_back(tab); | |
624 } | |
625 } | |
626 } | |
627 | |
628 Browser* StartupBrowserCreatorImpl::OpenURLsInBrowser( | |
629 Browser* browser, | |
630 bool process_startup, | |
631 const std::vector<GURL>& urls) { | |
632 StartupTabs tabs; | |
633 UrlsToTabs(urls, &tabs); | |
634 return OpenTabsInBrowser(browser, process_startup, tabs); | |
635 } | |
636 | |
637 Browser* StartupBrowserCreatorImpl::OpenTabsInBrowser(Browser* browser, | |
638 bool process_startup, | |
639 const StartupTabs& tabs) { | |
640 DCHECK(!tabs.empty()); | |
641 | |
642 // If we don't yet have a profile, try to use the one we're given from | |
643 // |browser|. While we may not end up actually using |browser| (since it | |
644 // could be a popup window), we can at least use the profile. | |
645 if (!profile_ && browser) | |
646 profile_ = browser->profile(); | |
647 | |
648 if (!browser || !browser->is_type_tabbed()) { | |
649 browser = Browser::Create(profile_); | |
650 } else { | |
651 #if defined(TOOLKIT_GTK) | |
652 // Setting the time of the last action on the window here allows us to steal | |
653 // focus, which is what the user wants when opening a new tab in an existing | |
654 // browser window. | |
655 gtk_util::SetWMLastUserActionTime(browser->window()->GetNativeHandle()); | |
656 #endif | |
657 } | |
658 | |
659 #if !defined(OS_MACOSX) | |
660 // In kiosk mode, we want to always be fullscreen, so switch to that now. | |
661 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) | |
662 browser->ToggleFullscreenMode(); | |
663 #endif | |
664 | |
665 bool first_tab = true; | |
666 for (size_t i = 0; i < tabs.size(); ++i) { | |
667 // We skip URLs that we'd have to launch an external protocol handler for. | |
668 // This avoids us getting into an infinite loop asking ourselves to open | |
669 // a URL, should the handler be (incorrectly) configured to be us. Anyone | |
670 // asking us to open such a URL should really ask the handler directly. | |
671 bool handled_by_chrome = ProfileIOData::IsHandledURL(tabs[i].url) || | |
672 (profile_ && profile_->GetProtocolHandlerRegistry()->IsHandledProtocol( | |
673 tabs[i].url.scheme())); | |
674 if (!process_startup && !handled_by_chrome) | |
675 continue; | |
676 | |
677 int add_types = first_tab ? TabStripModel::ADD_ACTIVE : | |
678 TabStripModel::ADD_NONE; | |
679 add_types |= TabStripModel::ADD_FORCE_INDEX; | |
680 if (tabs[i].is_pinned) | |
681 add_types |= TabStripModel::ADD_PINNED; | |
682 int index = browser->GetIndexForInsertionDuringRestore(i); | |
683 | |
684 browser::NavigateParams params(browser, tabs[i].url, | |
685 content::PAGE_TRANSITION_START_PAGE); | |
686 params.disposition = first_tab ? NEW_FOREGROUND_TAB : | |
687 NEW_BACKGROUND_TAB; | |
688 params.tabstrip_index = index; | |
689 params.tabstrip_add_types = add_types; | |
690 params.extension_app_id = tabs[i].app_id; | |
691 browser::Navigate(¶ms); | |
692 | |
693 first_tab = false; | |
694 } | |
695 if (!browser->GetSelectedWebContents()) { | |
696 // TODO: this is a work around for 110909. Figure out why it's needed. | |
697 if (!browser->tab_count()) | |
698 browser->AddBlankTab(true); | |
699 else | |
700 browser->ActivateTabAt(0, false); | |
701 } | |
702 | |
703 browser->window()->Show(); | |
704 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial | |
705 // focus explicitly. | |
706 browser->GetSelectedWebContents()->GetView()->SetInitialFocus(); | |
707 | |
708 return browser; | |
709 } | |
710 | |
711 void StartupBrowserCreatorImpl::AddInfoBarsIfNecessary( | |
712 Browser* browser, | |
713 browser::startup::IsProcessStartup is_process_startup) { | |
714 if (!browser || !profile_ || browser->tab_count() == 0) | |
715 return; | |
716 | |
717 if (HasPendingUncleanExit(browser->profile())) | |
718 browser::ShowSessionCrashedPrompt(browser); | |
719 | |
720 // The bad flags info bar and the obsolete system info bar are only added to | |
721 // the first profile which is launched. Other profiles might be restoring the | |
722 // browsing sessions asynchronously, so we cannot add the info bars to the | |
723 // focused tabs here. | |
724 if (is_process_startup == browser::startup::IS_PROCESS_STARTUP) { | |
725 browser::ShowBadFlagsPrompt(browser); | |
726 browser::ShowObsoleteOSPrompt(browser); | |
727 } | |
728 } | |
729 | |
730 | |
731 void StartupBrowserCreatorImpl::AddStartupURLs( | |
732 std::vector<GURL>* startup_urls) const { | |
733 // If we have urls specified beforehand (i.e. from command line) use them | |
734 // and nothing else. | |
735 if (!startup_urls->empty()) | |
736 return; | |
737 | |
738 // If we have urls specified by the first run master preferences use them | |
739 // and nothing else. | |
740 if (browser_creator_) { | |
741 if (!browser_creator_->first_run_tabs_.empty()) { | |
742 std::vector<GURL>::iterator it = | |
743 browser_creator_->first_run_tabs_.begin(); | |
744 while (it != browser_creator_->first_run_tabs_.end()) { | |
745 // Replace magic names for the actual urls. | |
746 if (it->host() == "new_tab_page") { | |
747 startup_urls->push_back(GURL(chrome::kChromeUINewTabURL)); | |
748 } else if (it->host() == "welcome_page") { | |
749 startup_urls->push_back(GetWelcomePageURL()); | |
750 } else { | |
751 startup_urls->push_back(*it); | |
752 } | |
753 ++it; | |
754 } | |
755 browser_creator_->first_run_tabs_.clear(); | |
756 } | |
757 } | |
758 | |
759 // Otherwise open at least the new tab page (and the welcome page, if this | |
760 // is the first time the browser is being started), or the set of URLs | |
761 // specified on the command line. | |
762 if (startup_urls->empty()) { | |
763 startup_urls->push_back(GURL(chrome::kChromeUINewTabURL)); | |
764 PrefService* prefs = g_browser_process->local_state(); | |
765 if (prefs->FindPreference(prefs::kShouldShowWelcomePage) && | |
766 prefs->GetBoolean(prefs::kShouldShowWelcomePage)) { | |
767 // Reset the preference so we don't show the welcome page next time. | |
768 prefs->ClearPref(prefs::kShouldShowWelcomePage); | |
769 startup_urls->push_back(GetWelcomePageURL()); | |
770 } | |
771 } | |
772 | |
773 // If the sync promo page is going to be displayed then insert it at the front | |
774 // of the list. | |
775 if (SyncPromoUI::ShouldShowSyncPromoAtStartup(profile_, is_first_run_)) { | |
776 SyncPromoUI::DidShowSyncPromoAtStartup(profile_); | |
777 GURL old_url = (*startup_urls)[0]; | |
778 (*startup_urls)[0] = | |
779 SyncPromoUI::GetSyncPromoURL(GURL(chrome::kChromeUINewTabURL), | |
780 SyncPromoUI::SOURCE_START_PAGE); | |
781 | |
782 // An empty URL means to go to the home page. | |
783 if (old_url.is_empty() && | |
784 profile_->GetHomePage() == GURL(chrome::kChromeUINewTabURL)) { | |
785 old_url = GURL(chrome::kChromeUINewTabURL); | |
786 } | |
787 | |
788 // If the old URL is not the NTP then insert it right after the sync promo. | |
789 if (old_url != GURL(chrome::kChromeUINewTabURL)) | |
790 startup_urls->insert(startup_urls->begin() + 1, old_url); | |
791 | |
792 // If we have more than two startup tabs then skip the welcome page. | |
793 if (startup_urls->size() > 2) { | |
794 std::vector<GURL>::iterator it = std::find( | |
795 startup_urls->begin(), startup_urls->end(), GetWelcomePageURL()); | |
796 if (it != startup_urls->end()) | |
797 startup_urls->erase(it); | |
798 } | |
799 } | |
800 } | |
801 | |
802 void StartupBrowserCreatorImpl::CheckPreferencesBackup(Profile* profile) { | |
803 ProtectorService* protector_service = | |
804 ProtectorServiceFactory::GetForProfile(profile); | |
805 ProtectedPrefsWatcher* prefs_watcher = protector_service->GetPrefsWatcher(); | |
806 | |
807 // Check if backup is valid. | |
808 if (!prefs_watcher->is_backup_valid()) { | |
809 protector_service->ShowChange(protector::CreatePrefsBackupInvalidChange()); | |
810 // Further checks make no sense. | |
811 return; | |
812 } | |
813 | |
814 // Check for session startup (including pinned tabs) changes. | |
815 if (SessionStartupPref::DidStartupPrefChange(profile) || | |
816 prefs_watcher->DidPrefChange(prefs::kPinnedTabs)) { | |
817 LOG(WARNING) << "Session startup settings have changed"; | |
818 SessionStartupPref new_pref = SessionStartupPref::GetStartupPref(profile); | |
819 StartupTabs new_tabs = PinnedTabCodec::ReadPinnedTabs(profile); | |
820 const base::Value* tabs_backup = | |
821 prefs_watcher->GetBackupForPref(prefs::kPinnedTabs); | |
822 protector_service->ShowChange(protector::CreateSessionStartupChange( | |
823 new_pref, | |
824 new_tabs, | |
825 SessionStartupPref::GetStartupPrefBackup(profile), | |
826 PinnedTabCodec::ReadPinnedTabs(tabs_backup))); | |
827 } | |
828 | |
829 // Check for homepage changes. | |
830 if (prefs_watcher->DidPrefChange(prefs::kHomePage) || | |
831 prefs_watcher->DidPrefChange(prefs::kHomePageIsNewTabPage) || | |
832 prefs_watcher->DidPrefChange(prefs::kShowHomeButton)) { | |
833 LOG(WARNING) << "Homepage has changed"; | |
834 PrefService* prefs = profile->GetPrefs(); | |
835 std::string backup_homepage; | |
836 bool backup_homepage_is_ntp; | |
837 bool backup_show_home_button; | |
838 if (!prefs_watcher->GetBackupForPref(prefs::kHomePage)-> | |
839 GetAsString(&backup_homepage) || | |
840 !prefs_watcher->GetBackupForPref(prefs::kHomePageIsNewTabPage)-> | |
841 GetAsBoolean(&backup_homepage_is_ntp) || | |
842 !prefs_watcher->GetBackupForPref(prefs::kShowHomeButton)-> | |
843 GetAsBoolean(&backup_show_home_button)) { | |
844 NOTREACHED(); | |
845 } | |
846 protector_service->ShowChange(protector::CreateHomepageChange( | |
847 // New: | |
848 prefs->GetString(prefs::kHomePage), | |
849 prefs->GetBoolean(prefs::kHomePageIsNewTabPage), | |
850 prefs->GetBoolean(prefs::kShowHomeButton), | |
851 // Backup: | |
852 backup_homepage, | |
853 backup_homepage_is_ntp, | |
854 backup_show_home_button)); | |
855 } | |
856 } | |
OLD | NEW |