Run Tizen Webapps in single process mode
[platform/framework/web/crosswalk-tizen.git] / atom / browser / atom_browser_main_parts.cc
1 // Copyright (c) 2013 GitHub, Inc.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
4
5 #include "atom/browser/atom_browser_main_parts.h"
6
7 #include "atom/browser/api/trackable_object.h"
8 #include "atom/browser/atom_access_token_store.h"
9 #include "atom/browser/atom_browser_client.h"
10 #include "atom/browser/atom_browser_context.h"
11 #include "atom/browser/atom_web_ui_controller_factory.h"
12 #include "atom/browser/bridge_task_runner.h"
13 #include "atom/browser/browser.h"
14 #include "atom/browser/javascript_environment.h"
15 #include "atom/browser/node_debugger.h"
16 #include "atom/common/api/atom_bindings.h"
17 #include "atom/common/asar/asar_util.h"
18 #include "atom/common/node_bindings.h"
19 #include "atom/common/node_includes.h"
20 #include "base/command_line.h"
21 #include "base/feature_list.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "chrome/browser/browser_process.h"
24 #include "content/public/browser/child_process_security_policy.h"
25 #include "device/geolocation/geolocation_delegate.h"
26 #include "device/geolocation/geolocation_provider.h"
27 #include "v8/include/v8-debug.h"
28
29 #include "gin/v8_initializer.h"
30
31 #if defined(USE_X11)
32 #include "chrome/browser/ui/libgtkui/gtk_util.h"
33 #include "ui/events/devices/x11/touch_factory_x11.h"
34 #endif
35
36 #if defined(USE_EFL)
37 #include "ui/display/screen_efl.h"
38 #endif
39
40 #include "atom/common/node_includes.h"
41
42 namespace atom {
43
44 namespace {
45
46 // A provider of Geolocation services to override AccessTokenStore.
47 class AtomGeolocationDelegate : public device::GeolocationDelegate {
48  public:
49   AtomGeolocationDelegate() = default;
50
51   scoped_refptr<device::AccessTokenStore> CreateAccessTokenStore() final {
52     return new AtomAccessTokenStore();
53   }
54
55  private:
56   DISALLOW_COPY_AND_ASSIGN(AtomGeolocationDelegate);
57 };
58
59 template<typename T>
60 void Erase(T* container, typename T::iterator iter) {
61   container->erase(iter);
62 }
63
64 // static - lines have been moved to limit their visibility only to this file
65 bool g_prelaunch = false;
66 node::Environment* env_ = nullptr;
67 scoped_refptr<BridgeTaskRunner> self_bridge_task_runner;
68 std::unique_ptr<Browser> self_browser;
69 std::unique_ptr<JavascriptEnvironment> self_js_env;
70 std::unique_ptr<NodeBindings> self_node_bindings;
71 std::unique_ptr<AtomBindings> self_atom_bindings;
72 std::unique_ptr<NodeEnvironment> self_node_env;
73 std::unique_ptr<NodeDebugger> self_node_debugger;
74
75 }  // namespace
76
77 AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr;
78
79 AtomBrowserMainParts::AtomBrowserMainParts()
80     : fake_browser_process_(new BrowserProcess),
81       exit_code_(nullptr),
82       gc_timer_(true, true) {
83   DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
84   if (g_prelaunch) {
85     browser_ = std::move(self_browser);
86     node_bindings_ = std::move(self_node_bindings);
87     atom_bindings_ = std::move(self_atom_bindings);
88
89     js_env_ = std::move(self_js_env);
90     js_env_->SetupLocker();
91     node_debugger_ = std::move(self_node_debugger);
92     bridge_task_runner_ = self_bridge_task_runner;
93     node_env_ = std::move(self_node_env);
94   } else {
95     browser_.reset(new Browser);
96     node_bindings_.reset(NodeBindings::Create(NodeBindings::BROWSER));
97     atom_bindings_.reset(new AtomBindings(node_bindings_->uv_loop()));
98   }
99   self_ = this;
100   // Register extension scheme as web safe scheme.
101   content::ChildProcessSecurityPolicy::GetInstance()->
102       RegisterWebSafeScheme("chrome-extension");
103 }
104
105 AtomBrowserMainParts::~AtomBrowserMainParts() {
106   asar::ClearArchives();
107   // Leak the JavascriptEnvironment on exit.
108   // This is to work around the bug that V8 would be waiting for background
109   // tasks to finish on exit, while somehow it waits forever in Electron, more
110   // about this can be found at https://github.com/electron/electron/issues/4767.
111   // On the other handle there is actually no need to gracefully shutdown V8
112   // on exit in the main process, we already ensured all necessary resources get
113   // cleaned up, and it would make quitting faster.
114   ignore_result(js_env_.release());
115 }
116
117 // static
118 AtomBrowserMainParts* AtomBrowserMainParts::Get() {
119   DCHECK(self_);
120   return self_;
121 }
122
123 Browser* AtomBrowserMainParts::GetStaticBrowser() {
124   return self_browser.get();
125 }
126
127 void AtomBrowserMainParts::SetNodeEnvironment() {
128   if (g_prelaunch)
129     return;
130
131   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
132   feature_list->InitializeFromCommandLine("", "");
133   base::FeatureList::SetInstance(std::move(feature_list));
134
135   gin::V8Initializer::LoadV8Snapshot();
136   gin::V8Initializer::LoadV8Natives();
137
138   self_browser.reset(new atom::Browser);
139   self_bridge_task_runner = new atom::BridgeTaskRunner;
140   base::ThreadTaskRunnerHandle handle(self_bridge_task_runner);
141
142   self_js_env.reset(new atom::JavascriptEnvironment);
143   self_node_bindings.reset(atom::NodeBindings::Create(atom::NodeBindings::BROWSER));
144   self_atom_bindings.reset(new atom::AtomBindings(self_node_bindings->uv_loop()));
145   self_node_bindings->Initialize();
146
147   self_node_debugger.reset(new atom::NodeDebugger(self_js_env->isolate(), self_node_bindings->uv_loop()));
148   env_ = self_node_bindings->CreateEnvironment(self_js_env->context());
149   self_node_env.reset(new atom::NodeEnvironment(env_));
150
151   if (self_node_debugger->IsRunning())
152     env_->AssignToContext(v8::Debug::GetDebugContext(self_js_env->isolate()));
153
154   self_atom_bindings->BindTo(self_js_env->isolate(), env_->process_object());
155
156   self_node_bindings->LoadEnvironment(env_);
157   self_node_bindings->set_uv_env(env_);
158   g_prelaunch = true;
159 }
160
161 bool AtomBrowserMainParts::SetExitCode(int code) {
162   if (!exit_code_)
163     return false;
164
165   *exit_code_ = code;
166   return true;
167 }
168
169 int AtomBrowserMainParts::GetExitCode() {
170   return exit_code_ != nullptr ? *exit_code_ : 0;
171 }
172
173 base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
174     const base::Closure& callback) {
175   auto iter = destructors_.insert(destructors_.end(), callback);
176   return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
177 }
178
179 void AtomBrowserMainParts::PreEarlyInitialization() {
180   brightray::BrowserMainParts::PreEarlyInitialization();
181 #if defined(OS_POSIX)
182   HandleSIGCHLD();
183 #endif
184 }
185
186 void AtomBrowserMainParts::PostEarlyInitialization() {
187   brightray::BrowserMainParts::PostEarlyInitialization();
188   if (g_prelaunch)
189       return;
190
191   // Temporary set the bridge_task_runner_ as current thread's task runner,
192   // so we can fool gin::PerIsolateData to use it as its task runner, instead
193   // of getting current message loop's task runner, which is null for now.
194   bridge_task_runner_ = new BridgeTaskRunner;
195   base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
196
197   // The ProxyResolverV8 has setup a complete V8 environment, in order to
198   // avoid conflicts we only initialize our V8 environment after that.
199   js_env_.reset(new JavascriptEnvironment);
200   js_env_->SetupLocker();
201
202   node_bindings_->Initialize();
203
204   // Support the "--debug" switch.
205   node_debugger_.reset(new NodeDebugger(js_env_->isolate(), node_bindings_->uv_loop()));
206
207   // Create the global environment.
208   node::Environment* env =
209       node_bindings_->CreateEnvironment(js_env_->context());
210   node_env_.reset(new NodeEnvironment(env));
211
212   // Make sure node can get correct environment when debugging.
213   if (node_debugger_->IsRunning())
214     env->AssignToContext(v8::Debug::GetDebugContext(js_env_->isolate()));
215
216   // Add Electron extended APIs.
217   atom_bindings_->BindTo(js_env_->isolate(), env->process_object());
218
219   // Load everything.
220   node_bindings_->LoadEnvironment(env);
221
222   // Wrap the uv loop with global env.
223   node_bindings_->set_uv_env(env);
224 }
225
226 void AtomBrowserMainParts::PreMainMessageLoopRun() {
227   js_env_->OnMessageLoopCreated();
228
229   // Run user's main script before most things get initialized, so we can have
230   // a chance to setup everything.
231   node_bindings_->PrepareMessageLoop();
232   node_bindings_->RunMessageLoop();
233
234 #if defined(USE_X11)
235   ui::TouchFactory::SetTouchDeviceListFromCommandLine();
236 #endif
237
238   // Start idle gc.
239   gc_timer_.Start(
240       FROM_HERE, base::TimeDelta::FromMinutes(1),
241       base::Bind(&v8::Isolate::LowMemoryNotification,
242                  base::Unretained(js_env_->isolate())));
243
244   content::WebUIControllerFactory::RegisterFactory(
245       AtomWebUIControllerFactory::GetInstance());
246
247   brightray::BrowserMainParts::PreMainMessageLoopRun();
248   bridge_task_runner_->MessageLoopIsReady();
249   bridge_task_runner_ = nullptr;
250
251 #if defined(USE_X11)
252   libgtkui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
253 #endif
254
255 #if defined(USE_EFL)
256   ui::InstallScreenInstance();
257 #endif
258
259 #if !defined(OS_MACOSX)
260   // The corresponding call in macOS is in AtomApplicationDelegate.
261   Browser::Get()->WillFinishLaunching();
262   std::unique_ptr<base::DictionaryValue> empty_info(new base::DictionaryValue);
263   Browser::Get()->DidFinishLaunching(*empty_info);
264 #endif
265 }
266
267 bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
268   exit_code_ = result_code;
269   return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
270 }
271
272 void AtomBrowserMainParts::PostMainMessageLoopStart() {
273   brightray::BrowserMainParts::PostMainMessageLoopStart();
274 #if defined(OS_POSIX)
275   HandleShutdownSignals();
276 #endif
277   device::GeolocationProvider::SetGeolocationDelegate(
278       new AtomGeolocationDelegate());
279 }
280
281 void AtomBrowserMainParts::PostMainMessageLoopRun() {
282   brightray::BrowserMainParts::PostMainMessageLoopRun();
283
284   js_env_->OnMessageLoopDestroying();
285
286 #if defined(OS_MACOSX)
287   FreeAppDelegate();
288 #endif
289
290   // Make sure destruction callbacks are called before message loop is
291   // destroyed, otherwise some objects that need to be deleted on IO thread
292   // won't be freed.
293   // We don't use ranged for loop because iterators are getting invalided when
294   // the callback runs.
295   for (auto iter = destructors_.begin(); iter != destructors_.end();) {
296     base::Closure& callback = *iter;
297     ++iter;
298     callback.Run();
299   }
300 }
301
302 }  // namespace atom