clang/win/asan: Remove /fallback and enable warnings-as-errors.
[chromium-blink-merge.git] / ios / web / app / web_main_loop.mm
blobb3300d4cf9320ad3ac79340e8f0c7f412fbd8c51
1 // Copyright 2014 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.
5 #include "ios/web/app/web_main_loop.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/metrics/histogram.h"
12 #include "base/path_service.h"
13 #include "base/power_monitor/power_monitor.h"
14 #include "base/power_monitor/power_monitor_device_source.h"
15 #include "base/process/process_metrics.h"
16 #include "base/system_monitor/system_monitor.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "crypto/nss_util.h"
19 #include "ios/web/net/cookie_notification_bridge.h"
20 #include "ios/web/public/app/web_main_parts.h"
21 #include "ios/web/public/web_client.h"
22 #include "ios/web/web_thread_impl.h"
23 #include "net/base/network_change_notifier.h"
25 namespace web {
27 // The currently-running WebMainLoop.  There can be one or zero.
28 // TODO(rohitrao): Desktop uses this to implement
29 // ImmediateShutdownAndExitProcess.  If we don't need that functionality, we can
30 // remove this.
31 WebMainLoop* g_current_web_main_loop = nullptr;
33 WebMainLoop::WebMainLoop() : result_code_(0), created_threads_(false) {
34   DCHECK(!g_current_web_main_loop);
35   g_current_web_main_loop = this;
38 WebMainLoop::~WebMainLoop() {
39   DCHECK_EQ(this, g_current_web_main_loop);
40   g_current_web_main_loop = nullptr;
43 void WebMainLoop::Init() {
44   parts_.reset(web::GetWebClient()->CreateWebMainParts());
47 void WebMainLoop::EarlyInitialization() {
48   if (parts_) {
49     parts_->PreEarlyInitialization();
50   }
52 #if !defined(USE_OPENSSL)
53   // We want to be sure to init NSPR on the main thread.
54   crypto::EnsureNSPRInit();
55 #endif  // !defined(USE_OPENSSL)
57   if (parts_) {
58     parts_->PostEarlyInitialization();
59   }
62 void WebMainLoop::MainMessageLoopStart() {
63   if (parts_) {
64     parts_->PreMainMessageLoopStart();
65   }
67   // Create a MessageLoop if one does not already exist for the current thread.
68   if (!base::MessageLoop::current()) {
69     main_message_loop_.reset(new base::MessageLoopForUI);
70   }
71   // Note: In Chrome, Attach() is called in
72   // ChromeBrowserMainPartsIOS::PreMainMessageLoopStart().
73   base::MessageLoopForUI::current()->Attach();
75   InitializeMainThread();
77 #if 0
78   // TODO(droger): SystemMonitor is not working properly on iOS.
79   // See http://crbug.com/228014.
80   system_monitor_.reset(new base::SystemMonitor);
81 #endif
82   // TODO(rohitrao): Do we need PowerMonitor on iOS, or can we get rid of it?
83   scoped_ptr<base::PowerMonitorSource> power_monitor_source(
84       new base::PowerMonitorDeviceSource());
85   power_monitor_.reset(new base::PowerMonitor(power_monitor_source.Pass()));
86   network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
88   if (parts_) {
89     parts_->PostMainMessageLoopStart();
90   }
93 void WebMainLoop::CreateStartupTasks() {
94   int result = 0;
95   result = PreCreateThreads();
96   if (result > 0)
97     return;
99   result = CreateThreads();
100   if (result > 0)
101     return;
103   result = WebThreadsStarted();
104   if (result > 0)
105     return;
107   result = PreMainMessageLoopRun();
108   if (result > 0)
109     return;
112 int WebMainLoop::PreCreateThreads() {
113   if (parts_) {
114     result_code_ = parts_->PreCreateThreads();
115   }
117   return result_code_;
120 int WebMainLoop::CreateThreads() {
121   base::Thread::Options default_options;
122   base::Thread::Options io_message_loop_options;
123   io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
124   base::Thread::Options ui_message_loop_options;
125   ui_message_loop_options.message_loop_type = base::MessageLoop::TYPE_UI;
127   // Start threads in the order they occur in the WebThread::ID
128   // enumeration, except for WebThread::UI which is the main
129   // thread.
130   //
131   // Must be size_t so we can increment it.
132   for (size_t thread_id = WebThread::UI + 1; thread_id < WebThread::ID_COUNT;
133        ++thread_id) {
134     scoped_ptr<WebThreadImpl>* thread_to_start = nullptr;
135     base::Thread::Options* options = &default_options;
137     switch (thread_id) {
138       // TODO(rohitrao): We probably do not need all of these threads.  Remove
139       // the ones that serve no purpose.  http://crbug.com/365909
140       case WebThread::DB:
141         thread_to_start = &db_thread_;
142         break;
143       case WebThread::FILE_USER_BLOCKING:
144         thread_to_start = &file_user_blocking_thread_;
145         break;
146       case WebThread::FILE:
147         thread_to_start = &file_thread_;
148         options = &io_message_loop_options;
149         break;
150       case WebThread::CACHE:
151         thread_to_start = &cache_thread_;
152         options = &io_message_loop_options;
153         break;
154       case WebThread::IO:
155         thread_to_start = &io_thread_;
156         options = &io_message_loop_options;
157         break;
158       case WebThread::UI:
159       case WebThread::ID_COUNT:
160       default:
161         NOTREACHED();
162         break;
163     }
165     WebThread::ID id = static_cast<WebThread::ID>(thread_id);
167     if (thread_to_start) {
168       (*thread_to_start).reset(new WebThreadImpl(id));
169       (*thread_to_start)->StartWithOptions(*options);
170     } else {
171       NOTREACHED();
172     }
173   }
174   created_threads_ = true;
175   return result_code_;
178 int WebMainLoop::PreMainMessageLoopRun() {
179   if (parts_) {
180     parts_->PreMainMessageLoopRun();
181   }
183   // If the UI thread blocks, the whole UI is unresponsive.
184   // Do not allow disk IO from the UI thread.
185   base::ThreadRestrictions::SetIOAllowed(false);
186   base::ThreadRestrictions::DisallowWaiting();
187   return result_code_;
190 void WebMainLoop::ShutdownThreadsAndCleanUp() {
191   if (!created_threads_) {
192     // Called early, nothing to do
193     return;
194   }
196   // Teardown may start in PostMainMessageLoopRun, and during teardown we
197   // need to be able to perform IO.
198   base::ThreadRestrictions::SetIOAllowed(true);
199   WebThread::PostTask(
200       WebThread::IO, FROM_HERE,
201       base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
202                  true));
204   if (parts_) {
205     parts_->PostMainMessageLoopRun();
206   }
208   // Must be size_t so we can subtract from it.
209   for (size_t thread_id = WebThread::ID_COUNT - 1;
210        thread_id >= (WebThread::UI + 1); --thread_id) {
211     // Find the thread object we want to stop. Looping over all valid
212     // WebThread IDs and DCHECKing on a missing case in the switch
213     // statement helps avoid a mismatch between this code and the
214     // WebThread::ID enumeration.
215     //
216     // The destruction order is the reverse order of occurrence in the
217     // WebThread::ID list. The rationale for the order is as
218     // follows (need to be filled in a bit):
219     //
220     //
221     // - The IO thread is the only user of the CACHE thread.
222     //
223     // - (Not sure why DB stops last.)
224     switch (thread_id) {
225       case WebThread::DB:
226         db_thread_.reset();
227         break;
228       case WebThread::FILE_USER_BLOCKING:
229         file_user_blocking_thread_.reset();
230         break;
231       case WebThread::FILE:
232         file_thread_.reset();
233         break;
234       case WebThread::CACHE:
235         cache_thread_.reset();
236         break;
237       case WebThread::IO:
238         io_thread_.reset();
239         break;
240       case WebThread::UI:
241       case WebThread::ID_COUNT:
242       default:
243         NOTREACHED();
244         break;
245     }
246   }
248   // Close the blocking I/O pool after the other threads. Other threads such
249   // as the I/O thread may need to schedule work like closing files or flushing
250   // data during shutdown, so the blocking pool needs to be available. There
251   // may also be slow operations pending that will block shutdown, so closing
252   // it here (which will block until required operations are complete) gives
253   // more head start for those operations to finish.
254   WebThreadImpl::ShutdownThreadPool();
256   if (parts_) {
257     parts_->PostDestroyThreads();
258   }
261 void WebMainLoop::InitializeMainThread() {
262   const char* kThreadName = "CrWebMain";
263   base::PlatformThread::SetName(kThreadName);
264   if (main_message_loop_) {
265     main_message_loop_->set_thread_name(kThreadName);
266   }
268   // Register the main thread by instantiating it, but don't call any methods.
269   main_thread_.reset(
270       new WebThreadImpl(WebThread::UI, base::MessageLoop::current()));
273 int WebMainLoop::WebThreadsStarted() {
274   cookie_notification_bridge_.reset(new CookieNotificationBridge);
275   return result_code_;
278 }  // namespace web