9f6622c05e2fecc487c5a74df20d21274c84219b
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / renderer / xwalk_extension_client.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/extensions/renderer/xwalk_extension_client.h"
6
7 #include "base/values.h"
8 #include "base/stl_util.h"
9 #include "ipc/ipc_sender.h"
10 #include "xwalk/extensions/common/xwalk_extension_messages.h"
11
12 namespace xwalk {
13 namespace extensions {
14
15 XWalkExtensionClient::XWalkExtensionClient()
16     : sender_(0),
17       next_instance_id_(1) {  // Zero is never used for a valid instance.
18 }
19
20 XWalkExtensionClient::~XWalkExtensionClient() {
21   STLDeleteValues(&extension_apis_);
22 }
23
24 bool XWalkExtensionClient::Send(IPC::Message* msg) {
25   DCHECK(sender_);
26
27   return sender_->Send(msg);
28 }
29
30 int64_t XWalkExtensionClient::CreateInstance(
31     const std::string& extension_name,
32     InstanceHandler* handler) {
33   CHECK(handler);
34   if (!Send(new XWalkExtensionServerMsg_CreateInstance(next_instance_id_,
35                                                        extension_name))) {
36     return 0;
37   }
38   handlers_[next_instance_id_] = handler;
39   return next_instance_id_++;
40 }
41
42 bool XWalkExtensionClient::OnMessageReceived(const IPC::Message& message) {
43   bool handled = true;
44   IPC_BEGIN_MESSAGE_MAP(XWalkExtensionClient, message)
45     IPC_MESSAGE_HANDLER(XWalkExtensionClientMsg_PostMessageToJS,
46         OnPostMessageToJS)
47     IPC_MESSAGE_HANDLER(XWalkExtensionClientMsg_PostOutOfLineMessageToJS,
48         OnPostOutOfLineMessageToJS)
49     IPC_MESSAGE_HANDLER(XWalkExtensionClientMsg_InstanceDestroyed,
50         OnInstanceDestroyed)
51     IPC_MESSAGE_UNHANDLED(handled = false)
52   IPC_END_MESSAGE_MAP()
53
54   return handled;
55 }
56
57 XWalkExtensionClient::ExtensionCodePoints::ExtensionCodePoints() {
58 }
59
60 XWalkExtensionClient::ExtensionCodePoints::~ExtensionCodePoints() {
61 }
62
63 void XWalkExtensionClient::OnPostMessageToJS(int64_t instance_id,
64                                              const base::ListValue& msg) {
65   HandlerMap::const_iterator it = handlers_.find(instance_id);
66   if (it == handlers_.end()) {
67     LOG(WARNING) << "Can't PostMessage to invalid Extension instance id: "
68                  << instance_id;
69     return;
70   }
71
72   // See comment in DestroyInstance() about two step destruction.
73   if (!it->second)
74     return;
75
76   const base::Value* value;
77   msg.Get(0, &value);
78   it->second->HandleMessageFromNative(*value);
79 }
80
81 void XWalkExtensionClient::OnPostOutOfLineMessageToJS(
82     base::SharedMemoryHandle handle, size_t size) {
83   CHECK(base::SharedMemory::IsHandleValid(handle));
84
85   base::SharedMemory shared_memory(handle, true);
86   shared_memory.Map(size);
87
88   IPC::Message message(static_cast<char*>(shared_memory.memory()), size);
89   OnMessageReceived(message);
90 }
91
92 void XWalkExtensionClient::DestroyInstance(int64_t instance_id) {
93   HandlerMap::iterator it = handlers_.find(instance_id);
94   if (it == handlers_.end() || !it->second) {
95     LOG(WARNING) << "Can't Destroy invalid instance id: " << instance_id;
96     return;
97   }
98   Send(new XWalkExtensionServerMsg_DestroyInstance(instance_id));
99
100   // Destruction happens in two steps, first we nullify the handler in our map,
101   // to indicate that destruction message was sent. If we get a new message from
102   // this instance, we can silently ignore. Later, we get a confirmation message
103   // from the server, only then we remove the entry from the map.
104   it->second = NULL;
105 }
106
107 void XWalkExtensionClient::OnInstanceDestroyed(int64_t instance_id) {
108   HandlerMap::iterator it = handlers_.find(instance_id);
109   if (it == handlers_.end()) {
110     LOG(WARNING) << "Got InstanceDestroyed msg for invalid instance id: "
111                  << instance_id;
112     return;
113   }
114
115   // Second part of the two step destruction. See DestroyInstance() for details.
116   // The system currently assumes that we always control the destruction of
117   // instances.
118   DCHECK(!it->second);
119   handlers_.erase(it);
120 }
121
122 namespace {
123
124 // Regular base::Value doesn't have param traits, so can't be passed as is
125 // through IPC. We wrap it in a base::ListValue that have traits before
126 // exchanging.
127 //
128 // Implementing param traits for base::Value is not a viable option at the
129 // moment (would require fork base::Value and create a new empty type).
130 scoped_ptr<base::ListValue> WrapValueInList(scoped_ptr<base::Value> value) {
131   if (!value)
132     return scoped_ptr<base::ListValue>();
133   scoped_ptr<base::ListValue> list_value(new base::ListValue);
134   list_value->Append(value.release());
135   return list_value.Pass();
136 }
137
138 }  // namespace
139
140 void XWalkExtensionClient::PostMessageToNative(int64_t instance_id,
141     scoped_ptr<base::Value> msg) {
142   scoped_ptr<base::ListValue> list_msg = WrapValueInList(msg.Pass());
143   Send(new XWalkExtensionServerMsg_PostMessageToNative(instance_id, *list_msg));
144 }
145
146 scoped_ptr<base::Value> XWalkExtensionClient::SendSyncMessageToNative(
147     int64_t instance_id, scoped_ptr<base::Value> msg) {
148   scoped_ptr<base::ListValue> wrapped_msg = WrapValueInList(msg.Pass());
149   base::ListValue* wrapped_reply = new base::ListValue;
150   Send(new XWalkExtensionServerMsg_SendSyncMessageToNative(instance_id,
151       *wrapped_msg, wrapped_reply));
152
153   scoped_ptr<base::Value> reply;
154   wrapped_reply->Remove(0, &reply);
155   return reply.Pass();
156 }
157
158 void XWalkExtensionClient::Initialize(IPC::Sender* sender) {
159   sender_ = sender;
160
161   std::vector<XWalkExtensionServerMsg_ExtensionRegisterParams> extensions;
162   Send(new XWalkExtensionServerMsg_GetExtensions(&extensions));
163
164   if (extensions.empty())
165     return;
166
167   std::vector<XWalkExtensionServerMsg_ExtensionRegisterParams>::iterator it =
168       extensions.begin();
169   for (; it != extensions.end(); ++it) {
170     ExtensionCodePoints* codepoint = new ExtensionCodePoints;
171     codepoint->api = (*it).js_api;
172
173     codepoint->entry_points = (*it).entry_points;
174
175     std::string name = (*it).name;
176     extension_apis_[name] = codepoint;
177   }
178 }
179
180 }  // namespace extensions
181 }  // namespace xwalk