Upstream version 5.34.97.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/application/browser/application.h"
6
7 #include <string>
8
9 #include "base/files/file_enumerator.h"
10 #include "base/json/json_reader.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "net/base/net_util.h"
18 #include "xwalk/application/browser/application_event_manager.h"
19 #include "xwalk/application/browser/application_service.h"
20 #include "xwalk/application/browser/application_storage.h"
21 #include "xwalk/application/browser/application_system.h"
22 #include "xwalk/application/common/application_manifest_constants.h"
23 #include "xwalk/application/common/constants.h"
24 #include "xwalk/application/common/manifest_handlers/main_document_handler.h"
25 #include "xwalk/application/common/event_names.h"
26 #include "xwalk/runtime/browser/runtime.h"
27 #include "xwalk/runtime/browser/runtime_context.h"
28 #include "xwalk/runtime/browser/xwalk_runner.h"
29
30 namespace xwalk {
31
32 namespace keys = application_manifest_keys;
33 namespace widget_keys = application_widget_keys;
34
35 namespace {
36 const char* kDefaultWidgetEntryPage[] = {
37 "index.html",
38 "index.htm",
39 "index.svg",
40 "index.xhtml",
41 "index.xht"};
42 const char kWidgetEntryPagePattern[] = "index.*";
43 }  // namespace
44
45 namespace application {
46
47 class FinishEventObserver : public EventObserver {
48  public:
49   FinishEventObserver(
50       ApplicationEventManager* event_manager,
51       Application* application)
52       : EventObserver(event_manager),
53         application_(application) {
54   }
55
56   virtual void Observe(const std::string& app_id,
57                        scoped_refptr<Event> event) OVERRIDE {
58     DCHECK(xwalk::application::kOnJavaScriptEventAck == event->name());
59     std::string ack_event_name;
60     event->args()->GetString(0, &ack_event_name);
61     if (ack_event_name == xwalk::application::kOnSuspend)
62       application_->CloseMainDocument();
63   }
64
65  private:
66   Application* application_;
67 };
68
69 Application::Application(
70     scoped_refptr<ApplicationData> data,
71     RuntimeContext* runtime_context,
72     Observer* observer)
73     : runtime_context_(runtime_context),
74       application_data_(data),
75       main_runtime_(NULL),
76       observer_(observer),
77       entry_point_used_(Default),
78       termination_mode_used_(Normal),
79       weak_factory_(this) {
80   DCHECK(runtime_context_);
81   DCHECK(application_data_);
82   DCHECK(observer_);
83 }
84
85 Application::~Application() {
86   Terminate(Immediate);
87 }
88
89 bool Application::Launch(const LaunchParams& launch_params) {
90   if (!runtimes_.empty()) {
91     LOG(ERROR) << "Attempt to launch app: " << id()
92                << " that was already launched.";
93     return false;
94   }
95
96   GURL url = GetURLForLaunch(launch_params, &entry_point_used_);
97   if (!url.is_valid())
98     return false;
99
100   main_runtime_ = Runtime::Create(runtime_context_, this);
101   main_runtime_->LoadURL(url);
102   if (entry_point_used_ != AppMainKey) {
103     NativeAppWindow::CreateParams params;
104     params.net_wm_pid = launch_params.launcher_pid;
105     main_runtime_->AttachWindow(params);
106   }
107
108   return true;
109 }
110
111 GURL Application::GetURLForLaunch(const LaunchParams& params,
112                                   LaunchEntryPoint* used) {
113   if (params.entry_points & AppMainKey) {
114     GURL url = GetURLFromAppMainKey();
115     if (url.is_valid()) {
116       *used = AppMainKey;
117       return url;
118     }
119   }
120
121   if (params.entry_points & LaunchLocalPathKey) {
122     GURL url = GetURLFromLocalPathKey();
123     if (url.is_valid()) {
124       *used = LaunchLocalPathKey;
125       return url;
126     }
127   }
128
129   if (params.entry_points & URLKey) {
130     GURL url = GetURLFromURLKey();
131     if (url.is_valid()) {
132       *used = URLKey;
133       return url;
134     }
135   }
136   LOG(WARNING) << "Failed to find a valid launch URL for the app.";
137   return GURL();
138 }
139
140 GURL Application::GetURLFromAppMainKey() {
141   MainDocumentInfo* main_info = ToMainDocumentInfo(
142     application_data_->GetManifestData(keys::kAppMainKey));
143   if (!main_info)
144     return GURL();
145
146   DCHECK(application_data_->HasMainDocument());
147   return main_info->GetMainURL();
148 }
149
150 GURL Application::GetURLFromLocalPathKey() {
151   const Manifest* manifest = application_data_->GetManifest();
152   std::string entry_page;
153   std::string key(GetLaunchLocalPathKey(
154       application_data_->GetPackageType()));
155
156   if (!manifest->GetString(key, &entry_page)
157       || entry_page.empty()) {
158     if (application_data_->GetPackageType() == Manifest::TYPE_XPK)
159       return GURL();
160
161     base::FileEnumerator iter(application_data_->Path(), true,
162                               base::FileEnumerator::FILES,
163                               FILE_PATH_LITERAL(kWidgetEntryPagePattern));
164     int priority = arraysize(kDefaultWidgetEntryPage);
165
166     for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
167       for (int i = 0; i < arraysize(kDefaultWidgetEntryPage); ++i) {
168         if (file.BaseName().MaybeAsASCII() == kDefaultWidgetEntryPage[i] &&
169             i < priority) {
170           entry_page = kDefaultWidgetEntryPage[i];
171           priority = i;
172         }
173       }
174     }
175
176     if (entry_page.empty())
177       return GURL();
178   }
179
180   return application_data_->GetResourceURL(entry_page);
181 }
182
183 GURL Application::GetURLFromURLKey() {
184   const Manifest* manifest = application_data_->GetManifest();
185   std::string url_string;
186   if (!manifest->GetString(keys::kURLKey, &url_string))
187     return GURL();
188
189   return GURL(url_string);
190 }
191
192 void Application::Terminate(TerminationMode mode) {
193   termination_mode_used_ = mode;
194   if (IsTerminating()) {
195     LOG(WARNING) << "Attempt to Terminate app: " << id()
196                  << ", which is already in the process of being terminated.";
197     if (mode == Immediate)
198       CloseMainDocument();
199
200     return;
201   }
202
203   std::set<Runtime*> to_be_closed(runtimes_);
204   if (HasMainDocument() && to_be_closed.size() > 1) {
205     // The main document runtime is closed separately
206     // (needs some extra logic) in Application::OnRuntimeRemoved.
207     to_be_closed.erase(main_runtime_);
208   }
209
210   std::for_each(to_be_closed.begin(), to_be_closed.end(),
211                 std::mem_fun(&Runtime::Close));
212 }
213
214 Runtime* Application::GetMainDocumentRuntime() const {
215   return HasMainDocument() ? main_runtime_ : NULL;
216 }
217
218 int Application::GetRenderProcessHostID() const {
219   DCHECK(main_runtime_);
220   return main_runtime_->web_contents()->
221           GetRenderProcessHost()->GetID();
222 }
223
224 bool Application::HasMainDocument() const {
225   return entry_point_used_ == AppMainKey;
226 }
227
228 void Application::OnRuntimeAdded(Runtime* runtime) {
229   DCHECK(runtime);
230   runtimes_.insert(runtime);
231 }
232
233 void Application::OnRuntimeRemoved(Runtime* runtime) {
234   DCHECK(runtime);
235   runtimes_.erase(runtime);
236
237   if (runtimes_.empty()) {
238 #if defined(OS_TIZEN)
239     runtime->CloseRootWindow();
240 #endif
241     base::MessageLoop::current()->PostTask(FROM_HERE,
242         base::Bind(&Application::NotifyTermination,
243                    weak_factory_.GetWeakPtr()));
244     return;
245   }
246
247   if (runtimes_.size() == 1 && HasMainDocument() &&
248       ContainsKey(runtimes_, main_runtime_)) {
249     ApplicationSystem* system = XWalkRunner::GetInstance()->app_system();
250     ApplicationEventManager* event_manager = system->event_manager();
251
252     // If onSuspend is not registered in main document,
253     // we close the main document immediately.
254     if (!IsOnSuspendHandlerRegistered() ||
255         termination_mode_used_ == Immediate) {
256       CloseMainDocument();
257       return;
258     }
259
260     DCHECK(!finish_observer_);
261     finish_observer_.reset(
262         new FinishEventObserver(event_manager, this));
263     event_manager->AttachObserver(
264         application_data_->ID(), kOnJavaScriptEventAck,
265         finish_observer_.get());
266
267     scoped_ptr<base::ListValue> event_args(new base::ListValue);
268     scoped_refptr<Event> event = Event::CreateEvent(
269         xwalk::application::kOnSuspend, event_args.Pass());
270     event_manager->SendEvent(application_data_->ID(), event);
271   }
272 }
273
274 void Application::CloseMainDocument() {
275   DCHECK(main_runtime_);
276
277   finish_observer_.reset();
278   main_runtime_->Close();
279   main_runtime_ = NULL;
280 }
281
282 void Application::NotifyTermination() {
283   observer_->OnApplicationTerminated(this);
284 }
285
286 bool Application::IsOnSuspendHandlerRegistered() const {
287   const std::set<std::string>& events = data()->GetEvents();
288   if (events.find(kOnSuspend) == events.end())
289     return false;
290
291   return true;
292 }
293
294 bool Application::UseExtension(const std::string& extension_name) const {
295   // TODO(Bai): Tells whether the application contains the specified extension
296   return true;
297 }
298
299 bool Application::RegisterPermissions(const std::string& extension_name,
300                                       const std::string& perm_table) {
301   // TODO(Bai): Parse the permission table and fill in the name_perm_map_
302   // The perm_table format is a simple JSON string, like
303   // [{"permission_name":"echo","apis":["add","remove","get"]}]
304   scoped_ptr<base::Value> root;
305   root.reset(base::JSONReader().ReadToValue(perm_table));
306   if (root.get() == NULL || !root->IsType(base::Value::TYPE_LIST))
307     return false;
308
309   base::ListValue* permission_list = static_cast<base::ListValue*>(root.get());
310   if (permission_list->GetSize() == 0)
311     return false;
312
313   for (base::ListValue::const_iterator iter = permission_list->begin();
314       iter != permission_list->end(); ++iter) {
315     if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY))
316         return false;
317
318     base::DictionaryValue* dict_val =
319         static_cast<base::DictionaryValue*>(*iter);
320     std::string permission_name;
321     if (!dict_val->GetString("permission_name", &permission_name))
322       return false;
323
324     base::ListValue* api_list = NULL;
325     if (!dict_val->GetList("apis", &api_list))
326       return false;
327
328     for (base::ListValue::const_iterator api_iter = api_list->begin();
329         api_iter != api_list->end(); ++api_iter) {
330       std::string api;
331       if (!((*api_iter)->IsType(base::Value::TYPE_STRING)
332           && (*api_iter)->GetAsString(&api)))
333         return false;
334       // register the permission and api
335       name_perm_map_[api] = permission_name;
336       DLOG(INFO) << "Permission Registered [PERM] " << permission_name
337                  << " [API] " << api;
338     }
339   }
340
341   return true;
342 }
343
344 std::string Application::GetRegisteredPermissionName(
345     const std::string& extension_name,
346     const std::string& api_name) const {
347   std::map<std::string, std::string>::const_iterator iter =
348       name_perm_map_.find(api_name);
349   if (iter == name_perm_map_.end())
350     return std::string("");
351   return iter->second;
352 }
353
354 StoredPermission Application::GetPermission(PermissionType type,
355                                std::string& permission_name) const {
356   if (type == SESSION_PERMISSION) {
357     StoredPermissionMap::const_iterator iter =
358         permission_map_.find(permission_name);
359     if (iter == permission_map_.end())
360       return UNDEFINED_STORED_PERM;
361     return iter->second;
362   }
363   if (type == PERSISTENT_PERMISSION) {
364     return application_data_->GetPermission(permission_name);
365   }
366   NOTREACHED();
367   return UNDEFINED_STORED_PERM;
368 }
369
370 bool Application::SetPermission(PermissionType type,
371                                 const std::string& permission_name,
372                                 StoredPermission perm) {
373   if (type == SESSION_PERMISSION) {
374     permission_map_[permission_name] = perm;
375     return true;
376   }
377   if (type == PERSISTENT_PERMISSION)
378     return application_data_->SetPermission(permission_name, perm);
379
380   NOTREACHED();
381   return false;
382 }
383
384 }  // namespace application
385 }  // namespace xwalk