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