1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "renderer/renderer_server.h"
31
32 #ifdef OS_WIN
33 #include <windows.h>
34 #endif // OS_WIN
35
36 #include <algorithm>
37
38 #include "base/compiler_specific.h"
39 #include "base/const.h"
40 #include "base/flags.h"
41 #include "base/logging.h"
42 #include "base/port.h"
43 #include "base/system_util.h"
44 #include "client/client_interface.h"
45 #include "config/config_handler.h"
46 #include "ipc/ipc.h"
47 #include "ipc/named_event.h"
48 #include "ipc/process_watch_dog.h"
49 #include "protocol/config.pb.h"
50 #include "protocol/renderer_command.pb.h"
51 #include "renderer/renderer_interface.h"
52
53 // By default, mozc_renderer quits when user-input continues to be
54 // idle for 10min.
55 DEFINE_int32(timeout, 10 * 60, "timeout of candidate server (sec)");
56 DEFINE_bool(restricted, false,
57 "launch candidates server with restricted mode");
58
59 namespace mozc {
60
61 namespace commands {
62 class Output;
63 class SessionCommand;
64 } // namespace commands
65
66 namespace renderer {
67
68 namespace {
69 #ifdef OS_WIN
70 const int kNumConnections = 1;
71 #else
72 const int kNumConnections = 10;
73 #endif // OS_WIN or not
74 const int kIPCServerTimeOut = 1000;
75 const char kServiceName[] = "renderer";
76
GetServiceName()77 string GetServiceName() {
78 string name = kServiceName;
79 const string desktop_name = SystemUtil::GetDesktopNameAsString();
80 if (!desktop_name.empty()) {
81 name += ".";
82 name += desktop_name;
83 }
84 return name;
85 }
86 } // namespace
87
88 class ParentApplicationWatchDog : public ProcessWatchDog {
89 public:
ParentApplicationWatchDog(RendererServer * renderer_server)90 explicit ParentApplicationWatchDog(RendererServer *renderer_server)
91 : renderer_server_(renderer_server) {}
~ParentApplicationWatchDog()92 virtual ~ParentApplicationWatchDog() {}
93
Signaled(ProcessWatchDog::SignalType type)94 void Signaled(ProcessWatchDog::SignalType type) {
95 if (renderer_server_ == NULL) {
96 LOG(ERROR) << "renderer_server is NULL";
97 return;
98 }
99 if (type == ProcessWatchDog::PROCESS_SIGNALED ||
100 type == ProcessWatchDog::THREAD_SIGNALED) {
101 VLOG(1) << "Parent process is terminated: call Hide event";
102 mozc::commands::RendererCommand command;
103 command.set_type(mozc::commands::RendererCommand::UPDATE);
104 command.set_visible(false);
105 string *buf = new string;
106 if (command.SerializeToString(buf)) {
107 renderer_server_->AsyncExecCommand(buf);
108 } else {
109 LOG(ERROR) << "SerializeToString failed";
110 delete buf;
111 }
112 }
113 }
114
115 private:
116 RendererServer *renderer_server_;
117 DISALLOW_COPY_AND_ASSIGN(ParentApplicationWatchDog);
118 };
119
120 class RendererServerSendCommand : public client::SendCommandInterface {
121 public:
RendererServerSendCommand()122 RendererServerSendCommand() : receiver_handle_(0) {}
~RendererServerSendCommand()123 virtual ~RendererServerSendCommand() {}
124
SendCommand(const mozc::commands::SessionCommand & command,mozc::commands::Output * output)125 bool SendCommand(const mozc::commands::SessionCommand &command,
126 mozc::commands::Output* output) {
127 #ifdef OS_WIN
128 if ((command.type() != commands::SessionCommand::SELECT_CANDIDATE) &&
129 (command.type() != commands::SessionCommand::HIGHLIGHT_CANDIDATE) &&
130 (command.type() != commands::SessionCommand::USAGE_STATS_EVENT)) {
131 // Unsupported command.
132 return false;
133 }
134
135 HWND target = reinterpret_cast<HWND>(receiver_handle_);
136 if (target == NULL) {
137 LOG(ERROR) << "target window is NULL";
138 return false;
139 }
140 UINT mozc_msg =
141 ::RegisterWindowMessageW(kMessageReceiverMessageName);
142 if (mozc_msg == 0) {
143 LOG(ERROR) << "RegisterWindowMessage failed: " << ::GetLastError();
144 return false;
145 }
146 if (command.type() == mozc::commands::SessionCommand::USAGE_STATS_EVENT) {
147 WPARAM type = static_cast<WPARAM>(command.type());
148 LPARAM event = static_cast<LPARAM>(command.usage_stats_event());
149 ::PostMessage(target, mozc_msg, type, event);
150 } else { // SELECT_CANDIDATE or HIGHLIGHT_CANDIDATE
151 WPARAM type = static_cast<WPARAM>(command.type());
152 LPARAM id = static_cast<LPARAM>(command.id());
153 ::PostMessage(target, mozc_msg, type, id);
154 }
155 #endif
156
157 // TODO(all): implementation for Mac/Linux
158 return true;
159 }
160
set_receiver_handle(uint32 receiver_handle)161 void set_receiver_handle(uint32 receiver_handle) {
162 receiver_handle_ = receiver_handle;
163 }
164
165 private:
166 uint32 receiver_handle_;
167 DISALLOW_COPY_AND_ASSIGN(RendererServerSendCommand);
168 };
169
RendererServer()170 RendererServer::RendererServer()
171 : IPCServer(GetServiceName(), kNumConnections, kIPCServerTimeOut),
172 timeout_(0),
173 renderer_interface_(NULL),
174 ALLOW_THIS_IN_INITIALIZER_LIST(
175 watch_dog_(new ParentApplicationWatchDog(this))),
176 send_command_(new RendererServerSendCommand) {
177 if (FLAGS_restricted) {
178 FLAGS_timeout =
179 std::min(FLAGS_timeout, 60); // set 60sec with restricted mode
180 }
181
182 timeout_ = 1000 * std::max(3, std::min(24 * 60 * 60, FLAGS_timeout));
183 VLOG(2) << "timeout is set to be : " << timeout_;
184
185 #ifndef NO_LOGGING
186 config::Config config;
187 config::ConfigHandler::GetConfig(&config);
188 Logging::SetConfigVerboseLevel(config.verbose_level());
189 #endif // NO_LOGGING
190 }
191
~RendererServer()192 RendererServer::~RendererServer() {}
193
SetRendererInterface(RendererInterface * renderer_interface)194 void RendererServer::SetRendererInterface(
195 RendererInterface *renderer_interface) {
196 renderer_interface_ = renderer_interface;
197 if (renderer_interface_ != NULL) {
198 renderer_interface_->SetSendCommandInterface(send_command_.get());
199 }
200 }
201
StartServer()202 int RendererServer::StartServer() {
203 if (!Connected()) {
204 LOG(ERROR) << "cannot start server";
205 return -1;
206 }
207
208 LoopAndReturn();
209
210 // send "ready" event to the client
211 const string name = GetServiceName();
212 NamedEventNotifier notifier(name.c_str());
213 notifier.Notify();
214
215 // start main event loop
216 return StartMessageLoop();
217 }
218
Process(const char * request,size_t request_size,char * response,size_t * response_size)219 bool RendererServer::Process(const char *request,
220 size_t request_size,
221 char *response,
222 size_t *response_size) {
223 // here we just copy the serialized message in order
224 // to reply to the client ui as soon as possible.
225 // ParseFromString is executed in the main(another) thread.
226 //
227 // Since Process() and ExecCommand() are executed in
228 // different threads, we have to use heap to share the serialized message.
229 // If we use stack, this program will be crashed.
230 //
231 // The reciver of command_str takes the ownership of this string.
232 string *command_str = new string(request, request_size);
233
234 // no need to set the result code.
235 *response_size = 1;
236 response[0] = '\0';
237
238 // Cannot call the method directly like renderer_interface_->ExecCommand()
239 // as it's not thread-safe.
240 return AsyncExecCommand(command_str);
241 }
242
ExecCommandInternal(const commands::RendererCommand & command)243 bool RendererServer::ExecCommandInternal(
244 const commands::RendererCommand &command) {
245 if (renderer_interface_ == NULL) {
246 LOG(ERROR) << "renderer_interface is NULL";
247 return false;
248 }
249
250 VLOG(2) << command.DebugString();
251
252 // Check process info if update mode
253 if (command.type() == commands::RendererCommand::UPDATE) {
254 // set HWND of message-only window
255 if (command.has_application_info() &&
256 command.application_info().has_receiver_handle()) {
257 send_command_->set_receiver_handle
258 (command.application_info().receiver_handle());
259 } else {
260 LOG(WARNING) << "receiver_handle is not set";
261 }
262
263 // watch the parent application.
264 if (command.has_application_info() &&
265 command.application_info().has_process_id() &&
266 command.application_info().has_thread_id()) {
267 if (!watch_dog_->SetID
268 (static_cast<ProcessWatchDog::ProcessID>
269 (command.application_info().process_id()),
270 static_cast<ProcessWatchDog::ThreadID>
271 (command.application_info().thread_id()), -1)) {
272 LOG(ERROR) << "Cannot set new ids for watch dog";
273 }
274 } else {
275 LOG(WARNING) << "process id and thread id are not set";
276 }
277 }
278
279 if (renderer_interface_->ExecCommand(command)) {
280 return true;
281 }
282
283 return false;
284 }
285
timeout() const286 uint32 RendererServer::timeout() const {
287 return timeout_;
288 }
289 } // namespace renderer
290 } // namespace mozc
291