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

Side by Side Diff: chrome/browser/browser_process_impl.cc

Issue 8477004: Have content/ create and destroy its own threads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More IWYU, missing link-time dependency for Chrome Frame. Created 9 years, 1 month 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "chrome/browser/browser_process_impl.h" 5 #include "chrome/browser/browser_process_impl.h"
6 6
7 #include <map> 7 #include <map>
8 #include <set> 8 #include <set>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 #include "chrome/common/chrome_switches.h" 63 #include "chrome/common/chrome_switches.h"
64 #include "chrome/common/default_plugin.h" 64 #include "chrome/common/default_plugin.h"
65 #include "chrome/common/extensions/extension_l10n_util.h" 65 #include "chrome/common/extensions/extension_l10n_util.h"
66 #include "chrome/common/extensions/extension_resource.h" 66 #include "chrome/common/extensions/extension_resource.h"
67 #include "chrome/common/json_pref_store.h" 67 #include "chrome/common/json_pref_store.h"
68 #include "chrome/common/pref_names.h" 68 #include "chrome/common/pref_names.h"
69 #include "chrome/common/switch_utils.h" 69 #include "chrome/common/switch_utils.h"
70 #include "chrome/common/url_constants.h" 70 #include "chrome/common/url_constants.h"
71 #include "chrome/installer/util/google_update_constants.h" 71 #include "chrome/installer/util/google_update_constants.h"
72 #include "content/browser/browser_child_process_host.h" 72 #include "content/browser/browser_child_process_host.h"
73 #include "content/browser/browser_process_sub_thread.h"
74 #include "content/browser/child_process_security_policy.h" 73 #include "content/browser/child_process_security_policy.h"
75 #include "content/browser/debugger/devtools_manager.h" 74 #include "content/browser/debugger/devtools_manager.h"
76 #include "content/browser/download/download_file_manager.h" 75 #include "content/browser/download/download_file_manager.h"
77 #include "content/browser/download/download_status_updater.h" 76 #include "content/browser/download/download_status_updater.h"
78 #include "content/browser/download/mhtml_generation_manager.h" 77 #include "content/browser/download/mhtml_generation_manager.h"
79 #include "content/browser/download/save_file_manager.h" 78 #include "content/browser/download/save_file_manager.h"
80 #include "content/browser/gpu/gpu_process_host_ui_shim.h" 79 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
81 #include "content/browser/net/browser_online_state_observer.h" 80 #include "content/browser/net/browser_online_state_observer.h"
82 #include "content/browser/plugin_service.h" 81 #include "content/browser/plugin_service.h"
83 #include "content/browser/renderer_host/render_process_host.h" 82 #include "content/browser/renderer_host/render_process_host.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 // Linux. We have a timeout here because we're unable to run the UI messageloop 125 // Linux. We have a timeout here because we're unable to run the UI messageloop
127 // and there's some deadlock risk. Our only option is to exit anyway. 126 // and there's some deadlock risk. Our only option is to exit anyway.
128 static const int kEndSessionTimeoutSeconds = 10; 127 static const int kEndSessionTimeoutSeconds = 10;
129 #endif 128 #endif
130 129
131 using content::BrowserThread; 130 using content::BrowserThread;
132 131
133 BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line) 132 BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
134 : created_resource_dispatcher_host_(false), 133 : created_resource_dispatcher_host_(false),
135 created_metrics_service_(false), 134 created_metrics_service_(false),
136 created_io_thread_(false),
137 created_file_thread_(false),
138 created_db_thread_(false),
139 created_process_launcher_thread_(false),
140 created_cache_thread_(false),
141 created_watchdog_thread_(false), 135 created_watchdog_thread_(false),
142 #if defined(OS_CHROMEOS)
143 created_web_socket_proxy_thread_(false),
144 #endif
145 created_profile_manager_(false), 136 created_profile_manager_(false),
146 created_local_state_(false), 137 created_local_state_(false),
147 created_icon_manager_(false), 138 created_icon_manager_(false),
148 created_devtools_manager_(false), 139 created_devtools_manager_(false),
149 created_sidebar_manager_(false), 140 created_sidebar_manager_(false),
150 created_browser_policy_connector_(false), 141 created_browser_policy_connector_(false),
151 created_notification_ui_manager_(false), 142 created_notification_ui_manager_(false),
152 created_safe_browsing_service_(false), 143 created_safe_browsing_service_(false),
153 module_ref_count_(0), 144 module_ref_count_(0),
154 did_start_(false), 145 did_start_(false),
(...skipping 13 matching lines...) Expand all
168 chrome::kExtensionScheme); 159 chrome::kExtensionScheme);
169 160
170 extension_event_router_forwarder_ = new ExtensionEventRouterForwarder; 161 extension_event_router_forwarder_ = new ExtensionEventRouterForwarder;
171 162
172 ExtensionTabIdMap::GetInstance()->Init(); 163 ExtensionTabIdMap::GetInstance()->Init();
173 164
174 online_state_observer_.reset(new BrowserOnlineStateObserver); 165 online_state_observer_.reset(new BrowserOnlineStateObserver);
175 } 166 }
176 167
177 BrowserProcessImpl::~BrowserProcessImpl() { 168 BrowserProcessImpl::~BrowserProcessImpl() {
178 #if defined(OS_CHROMEOS) 169 // See StartTearDown and PreStopThread functions below, this is where
179 if (web_socket_proxy_thread_.get()) 170 // most destruction happens so that it can be interleaved with threads
180 chromeos::WebSocketProxyController::Shutdown(); 171 // going away.
181 web_socket_proxy_thread_.reset();
182 #endif
183 172
173 // Wait for the pending print jobs to finish.
174 print_job_manager_->OnQuit();
175 print_job_manager_.reset();
176
177 // Destroy TabCloseableStateWatcher before NotificationService since the
178 // former registers for notifications.
179 tab_closeable_state_watcher_.reset();
180
181 g_browser_process = NULL;
182 }
183
184 void BrowserProcessImpl::StartTearDown() {
184 // Delete the AutomationProviderList before NotificationService, 185 // Delete the AutomationProviderList before NotificationService,
185 // since it may try to unregister notifications 186 // since it may try to unregister notifications
186 // Both NotificationService and AutomationProvider are singleton instances in 187 // Both NotificationService and AutomationProvider are singleton instances in
187 // the BrowserProcess. Since AutomationProvider may have some active 188 // the BrowserProcess. Since AutomationProvider may have some active
188 // notification observers, it is essential that it gets destroyed before the 189 // notification observers, it is essential that it gets destroyed before the
189 // NotificationService. NotificationService won't be destroyed until after 190 // NotificationService. NotificationService won't be destroyed until after
190 // this destructor is run. 191 // this destructor is run.
191 automation_provider_list_.reset(); 192 automation_provider_list_.reset();
192 193
193 // We need to shutdown the SdchDictionaryFetcher as it regularly holds 194 // We need to shutdown the SdchDictionaryFetcher as it regularly holds
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 browser_policy_connector_.reset(); 248 browser_policy_connector_.reset();
248 249
249 // Destroying the GpuProcessHostUIShims on the UI thread posts a task to 250 // Destroying the GpuProcessHostUIShims on the UI thread posts a task to
250 // delete related objects on the GPU thread. This must be done before 251 // delete related objects on the GPU thread. This must be done before
251 // stopping the GPU thread. The GPU thread will close IPC channels to renderer 252 // stopping the GPU thread. The GPU thread will close IPC channels to renderer
252 // processes so this has to happen before stopping the IO thread. 253 // processes so this has to happen before stopping the IO thread.
253 GpuProcessHostUIShim::DestroyAll(); 254 GpuProcessHostUIShim::DestroyAll();
254 255
255 // Stop the watchdog thread before stopping other threads. 256 // Stop the watchdog thread before stopping other threads.
256 watchdog_thread_.reset(); 257 watchdog_thread_.reset();
258 }
257 259
258 // Need to stop io_thread_ before resource_dispatcher_host_, since 260 void BrowserProcessImpl::PreStopThread(BrowserThread::ID thread_id) {
259 // io_thread_ may still deref ResourceDispatcherHost and handle resource 261 switch (thread_id) {
260 // request before going away. 262 #if defined(OS_CHROMEOS)
261 io_thread_.reset(); 263 case BrowserThread::WEB_SOCKET_PROXY:
264 chromeos::WebSocketProxyController::Shutdown();
265 break;
266 #endif
267 case BrowserThread::FILE:
268 // Clean up state that lives on the file_thread_ before it goes away.
269 if (resource_dispatcher_host_.get()) {
270 resource_dispatcher_host()->download_file_manager()->Shutdown();
271 resource_dispatcher_host()->save_file_manager()->Shutdown();
272 }
273 break;
274 case BrowserThread::WEBKIT:
275 // Need to destroy ResourceDispatcherHost before PluginService
276 // and SafeBrowsingService, since it caches a pointer to
277 // it. This also causes the webkit thread to terminate (which is
278 // still the responsibility of the embedder, not of the content
279 // framework).
280 resource_dispatcher_host_.reset();
281 break;
282 case BrowserThread::IO:
283 // Reset associated state right before actual thread is stopped,
284 // as some state cleanup may rely on the thread still running.
285 io_thread_.reset();
286 break;
287 default:
288 break;
289 }
290 }
262 291
263 // The IO thread was the only user of this thread. 292 void BrowserProcessImpl::PostStopThread(BrowserThread::ID thread_id) {
264 cache_thread_.reset(); 293 switch (thread_id) {
265 294 case BrowserThread::FILE:
266 // Stop the process launcher thread after the IO thread, in case the IO thread 295 // With the file_thread_ flushed, we can release any icon resources.
267 // posted a task to terminate a process on the process launcher thread. 296 icon_manager_.reset();
268 process_launcher_thread_.reset(); 297 break;
269 298 default:
270 // Clean up state that lives on the file_thread_ before it goes away. 299 break;
271 if (resource_dispatcher_host_.get()) {
272 resource_dispatcher_host()->download_file_manager()->Shutdown();
273 resource_dispatcher_host()->save_file_manager()->Shutdown();
274 } 300 }
275
276 // Need to stop the file_thread_ here to force it to process messages in its
277 // message loop from the previous call to shutdown the DownloadFileManager,
278 // SaveFileManager and SessionService.
279 file_thread_.reset();
280
281 // With the file_thread_ flushed, we can release any icon resources.
282 icon_manager_.reset();
283
284 // Need to destroy ResourceDispatcherHost before PluginService and
285 // SafeBrowsingService, since it caches a pointer to it. This also
286 // causes the webkit thread to terminate.
287 resource_dispatcher_host_.reset();
288
289 // Wait for the pending print jobs to finish.
290 print_job_manager_->OnQuit();
291 print_job_manager_.reset();
292
293 // Destroy TabCloseableStateWatcher before NotificationService since the
294 // former registers for notifications.
295 tab_closeable_state_watcher_.reset();
296
297 g_browser_process = NULL;
298 } 301 }
299 302
300 #if defined(OS_WIN) 303 #if defined(OS_WIN)
301 // Send a QuitTask to the given MessageLoop when the (file) thread has processed 304 // Send a QuitTask to the given MessageLoop when the (file) thread has processed
302 // our (other) recent requests (to save preferences). 305 // our (other) recent requests (to save preferences).
303 // Change the boolean so that the receiving thread will know that we did indeed 306 // Change the boolean so that the receiving thread will know that we did indeed
304 // send the QuitTask that terminated the message loop. 307 // send the QuitTask that terminated the message loop.
305 static void PostQuit(MessageLoop* message_loop) { 308 static void PostQuit(MessageLoop* message_loop) {
306 g_end_session_file_thread_has_completed = true; 309 g_end_session_file_thread_has_completed = true;
307 message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 310 message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 403
401 MetricsService* BrowserProcessImpl::metrics_service() { 404 MetricsService* BrowserProcessImpl::metrics_service() {
402 DCHECK(CalledOnValidThread()); 405 DCHECK(CalledOnValidThread());
403 if (!created_metrics_service_) 406 if (!created_metrics_service_)
404 CreateMetricsService(); 407 CreateMetricsService();
405 return metrics_service_.get(); 408 return metrics_service_.get();
406 } 409 }
407 410
408 IOThread* BrowserProcessImpl::io_thread() { 411 IOThread* BrowserProcessImpl::io_thread() {
409 DCHECK(CalledOnValidThread()); 412 DCHECK(CalledOnValidThread());
410 if (!created_io_thread_) 413 DCHECK(io_thread_.get());
411 CreateIOThread();
412 return io_thread_.get(); 414 return io_thread_.get();
413 } 415 }
414 416
415 base::Thread* BrowserProcessImpl::file_thread() { 417 base::Thread* BrowserProcessImpl::file_thread() {
416 DCHECK(CalledOnValidThread()); 418 DCHECK(CalledOnValidThread());
417 if (!created_file_thread_) 419 return BrowserThread::UnsafeGetBrowserThread(BrowserThread::FILE);
418 CreateFileThread();
419 return file_thread_.get();
420 } 420 }
421 421
422 base::Thread* BrowserProcessImpl::db_thread() { 422 base::Thread* BrowserProcessImpl::db_thread() {
423 DCHECK(CalledOnValidThread()); 423 DCHECK(CalledOnValidThread());
424 if (!created_db_thread_) 424 return BrowserThread::UnsafeGetBrowserThread(BrowserThread::DB);
425 CreateDBThread();
426 return db_thread_.get();
427 } 425 }
428 426
429 base::Thread* BrowserProcessImpl::process_launcher_thread() { 427 base::Thread* BrowserProcessImpl::process_launcher_thread() {
430 DCHECK(CalledOnValidThread()); 428 DCHECK(CalledOnValidThread());
431 if (!created_process_launcher_thread_) 429 return BrowserThread::UnsafeGetBrowserThread(BrowserThread::PROCESS_LAUNCHER);
432 CreateProcessLauncherThread();
433 return process_launcher_thread_.get();
434 } 430 }
435 431
436 base::Thread* BrowserProcessImpl::cache_thread() { 432 base::Thread* BrowserProcessImpl::cache_thread() {
437 DCHECK(CalledOnValidThread()); 433 DCHECK(CalledOnValidThread());
438 if (!created_cache_thread_) 434 return BrowserThread::UnsafeGetBrowserThread(BrowserThread::CACHE);
439 CreateCacheThread();
440 return cache_thread_.get();
441 } 435 }
442 436
443 WatchDogThread* BrowserProcessImpl::watchdog_thread() { 437 WatchDogThread* BrowserProcessImpl::watchdog_thread() {
444 DCHECK(CalledOnValidThread()); 438 DCHECK(CalledOnValidThread());
445 if (!created_watchdog_thread_) 439 if (!created_watchdog_thread_)
446 CreateWatchdogThread(); 440 CreateWatchdogThread();
447 DCHECK(watchdog_thread_.get() != NULL); 441 DCHECK(watchdog_thread_.get() != NULL);
448 return watchdog_thread_.get(); 442 return watchdog_thread_.get();
449 } 443 }
450 444
451 #if defined(OS_CHROMEOS) 445 #if defined(OS_CHROMEOS)
452 base::Thread* BrowserProcessImpl::web_socket_proxy_thread() { 446 base::Thread* BrowserProcessImpl::web_socket_proxy_thread() {
453 DCHECK(CalledOnValidThread()); 447 DCHECK(CalledOnValidThread());
454 if (!created_web_socket_proxy_thread_) 448 return BrowserThread::UnsafeGetBrowserThread(BrowserThread::WEB_SOCKET_PROXY);
455 CreateWebSocketProxyThread();
456 DCHECK(web_socket_proxy_thread_.get() != NULL);
457 return web_socket_proxy_thread_.get();
458 } 449 }
459 #endif 450 #endif
460 451
461 ProfileManager* BrowserProcessImpl::profile_manager() { 452 ProfileManager* BrowserProcessImpl::profile_manager() {
462 DCHECK(CalledOnValidThread()); 453 DCHECK(CalledOnValidThread());
463 if (!created_profile_manager_) 454 if (!created_profile_manager_)
464 CreateProfileManager(); 455 CreateProfileManager();
465 return profile_manager_.get(); 456 return profile_manager_.get();
466 } 457 }
467 458
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 ApplyAllowCrossOriginAuthPromptPolicy(); 764 ApplyAllowCrossOriginAuthPromptPolicy();
774 } 765 }
775 766
776 void BrowserProcessImpl::CreateMetricsService() { 767 void BrowserProcessImpl::CreateMetricsService() {
777 DCHECK(!created_metrics_service_ && metrics_service_.get() == NULL); 768 DCHECK(!created_metrics_service_ && metrics_service_.get() == NULL);
778 created_metrics_service_ = true; 769 created_metrics_service_ = true;
779 770
780 metrics_service_.reset(new MetricsService); 771 metrics_service_.reset(new MetricsService);
781 } 772 }
782 773
783 void BrowserProcessImpl::CreateIOThread() { 774 void BrowserProcessImpl::CreateIOThreadState() {
784 DCHECK(!created_io_thread_ && io_thread_.get() == NULL); 775 DCHECK(!io_thread_.get());
785 created_io_thread_ = true;
786 776
787 // Prior to starting the io thread, we create the plugin service as 777 // Prior to starting the io thread, we create the plugin service as
788 // it is predominantly used from the io thread, but must be created 778 // it is predominantly used from the io thread, but must be created
789 // on the main thread. The service ctor is inexpensive and does not 779 // on the main thread. The service ctor is inexpensive and does not
790 // invoke the io_thread() accessor. 780 // invoke the io_thread() accessor.
791 PluginService* plugin_service = PluginService::GetInstance(); 781 PluginService* plugin_service = PluginService::GetInstance();
792 plugin_service->set_filter(ChromePluginServiceFilter::GetInstance()); 782 plugin_service->set_filter(ChromePluginServiceFilter::GetInstance());
793 plugin_service->StartWatchingPlugins(); 783 plugin_service->StartWatchingPlugins();
794 784
795 // Add the Chrome specific plugins. 785 // Add the Chrome specific plugins.
(...skipping 12 matching lines...) Expand all
808 // e.g. ~/.config/chromium/Plugins. 798 // e.g. ~/.config/chromium/Plugins.
809 FilePath user_data_dir; 799 FilePath user_data_dir;
810 if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { 800 if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
811 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir( 801 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(
812 user_data_dir.Append("Plugins")); 802 user_data_dir.Append("Plugins"));
813 } 803 }
814 #endif 804 #endif
815 805
816 scoped_ptr<IOThread> thread(new IOThread( 806 scoped_ptr<IOThread> thread(new IOThread(
817 local_state(), net_log_.get(), extension_event_router_forwarder_.get())); 807 local_state(), net_log_.get(), extension_event_router_forwarder_.get()));
818 base::Thread::Options options;
819 options.message_loop_type = MessageLoop::TYPE_IO;
820 if (!thread->StartWithOptions(options))
821 return;
822 io_thread_.swap(thread); 808 io_thread_.swap(thread);
823 } 809 }
824 810
825 void BrowserProcessImpl::CreateFileThread() {
826 DCHECK(!created_file_thread_ && file_thread_.get() == NULL);
827 created_file_thread_ = true;
828
829 scoped_ptr<base::Thread> thread(
830 new content::BrowserProcessSubThread(BrowserThread::FILE));
831 base::Thread::Options options;
832 #if defined(OS_WIN)
833 // On Windows, the FILE thread needs to be have a UI message loop which pumps
834 // messages in such a way that Google Update can communicate back to us.
835 options.message_loop_type = MessageLoop::TYPE_UI;
836 #else
837 options.message_loop_type = MessageLoop::TYPE_IO;
838 #endif
839 if (!thread->StartWithOptions(options))
840 return;
841 file_thread_.swap(thread);
842 }
843
844 #if defined(OS_CHROMEOS)
845 void BrowserProcessImpl::CreateWebSocketProxyThread() {
846 DCHECK(!created_web_socket_proxy_thread_);
847 DCHECK(web_socket_proxy_thread_.get() == NULL);
848 created_web_socket_proxy_thread_ = true;
849
850 scoped_ptr<base::Thread> thread(
851 new content::BrowserProcessSubThread(BrowserThread::WEB_SOCKET_PROXY));
852 base::Thread::Options options;
853 options.message_loop_type = MessageLoop::TYPE_IO;
854 if (!thread->StartWithOptions(options))
855 return;
856 web_socket_proxy_thread_.swap(thread);
857 }
858 #endif
859
860 void BrowserProcessImpl::CreateDBThread() {
861 DCHECK(!created_db_thread_ && db_thread_.get() == NULL);
862 created_db_thread_ = true;
863
864 scoped_ptr<base::Thread> thread(
865 new content::BrowserProcessSubThread(BrowserThread::DB));
866 if (!thread->Start())
867 return;
868 db_thread_.swap(thread);
869 }
870
871 void BrowserProcessImpl::CreateProcessLauncherThread() {
872 DCHECK(!created_process_launcher_thread_ && !process_launcher_thread_.get());
873 created_process_launcher_thread_ = true;
874
875 scoped_ptr<base::Thread> thread(
876 new content::BrowserProcessSubThread(BrowserThread::PROCESS_LAUNCHER));
877 if (!thread->Start())
878 return;
879 process_launcher_thread_.swap(thread);
880 }
881
882 void BrowserProcessImpl::CreateCacheThread() {
883 DCHECK(!created_cache_thread_ && !cache_thread_.get());
884 created_cache_thread_ = true;
885
886 scoped_ptr<base::Thread> thread(
887 new content::DeprecatedBrowserThread(BrowserThread::CACHE));
888 base::Thread::Options options;
889 options.message_loop_type = MessageLoop::TYPE_IO;
890 if (!thread->StartWithOptions(options))
891 return;
892 cache_thread_.swap(thread);
893 }
894
895 void BrowserProcessImpl::CreateWatchdogThread() { 811 void BrowserProcessImpl::CreateWatchdogThread() {
896 DCHECK(!created_watchdog_thread_ && watchdog_thread_.get() == NULL); 812 DCHECK(!created_watchdog_thread_ && watchdog_thread_.get() == NULL);
897 created_watchdog_thread_ = true; 813 created_watchdog_thread_ = true;
898 814
899 scoped_ptr<WatchDogThread> thread(new WatchDogThread()); 815 scoped_ptr<WatchDogThread> thread(new WatchDogThread());
900 if (!thread->Start()) 816 if (!thread->Start())
901 return; 817 return;
902 watchdog_thread_.swap(thread); 818 watchdog_thread_.swap(thread);
903 } 819 }
904 820
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
1154 } 1070 }
1155 1071
1156 void BrowserProcessImpl::OnAutoupdateTimer() { 1072 void BrowserProcessImpl::OnAutoupdateTimer() {
1157 if (CanAutorestartForUpdate()) { 1073 if (CanAutorestartForUpdate()) {
1158 DLOG(WARNING) << "Detected update. Restarting browser."; 1074 DLOG(WARNING) << "Detected update. Restarting browser.";
1159 RestartBackgroundInstance(); 1075 RestartBackgroundInstance();
1160 } 1076 }
1161 } 1077 }
1162 1078
1163 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) 1079 #endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698