1
// Copyright 2010, Google Inc.
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
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
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.
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.
30
#include "client/session.h"
37
#include "third_party/mozc/sandbox/restricted_token_utils.h"
39
#include <spawn.h> // for posix_spawnp().
42
#include <sys/types.h>
45
#include "base/base.h"
46
#include "base/const.h"
47
#include "base/file_stream.h"
48
#include "base/process.h"
49
#include "base/run_level.h"
50
#include "base/util.h"
52
#include "ipc/named_event.h"
54
#include "base/mac_util.h"
60
const char kServerName[] = "session";
62
// Wait at most kServerWaitTimeout msec until server gets ready
63
const uint32 kServerWaitTimeout = 20000; // 20 sec
65
// for every 1000m sec, check server
66
const uint32 kRetryIntervalForServer = 1000;
68
// Try 20 times to check mozc_server is running
69
const uint32 kTrial = 20;
72
// Load special flags for server.
73
// This should be enabled on debug build
74
const string LoadServerFlags() {
75
const char kServerFlagsFile[] = "mozc_server_flags.txt";
76
const string filename = Util::JoinPath(Util::GetUserProfileDirectory(),
79
InputFileStream ifs(filename.c_str());
83
VLOG(1) << "New server flag: " << flags;
89
// initialize default path
90
StartServerHandler::StartServerHandler()
91
: server_program_(Util::GetServerPath()),
94
StartServerHandler::~StartServerHandler() {}
96
bool StartServerHandler::StartServer(SessionInterface *session) {
97
if (server_program().empty()) {
98
LOG(ERROR) << "Server path is empty";
103
if (session->PingServer()) {
110
// When mozc is not used as a default IME and some applications (like notepad)
111
// are registered in "Start up", mozc_server may not be launched successfully.
112
// This is because the Explorer launches start-up processes inside a group job
113
// and the process inside a job cannot make our sandboxed child processes.
114
// The group job is unregistered after 60 secs (default).
116
// Here we relax the sandbox restriction if process is in a job.
117
// In order to keep security, the mozc_server is launched
118
// with restricted mode.
120
const bool process_in_job = RunLevel::IsProcessInJob();
121
if (process_in_job || restricted_) {
123
<< "Parent process is in job. start with restricted mode";
124
arg += "--restricted";
129
// In oreder to test the Session treatment (timeout/size constratins),
130
// Server flags can be configurable on DEBUG build
134
arg += LoadServerFlags();
137
NamedEventListener listener(kServerName);
138
const bool listener_is_available = listener.IsAvailable();
142
mozc::Process::SecurityInfo info;
143
info.primary_level = sandbox::USER_INTERACTIVE;
144
info.impersonation_level = sandbox::USER_RESTRICTED_SAME_ACCESS;
145
info.job_level = process_in_job ?
146
sandbox::JOB_NO_JOB : sandbox::JOB_LOCKDOWN;
147
info.integrity_level = sandbox::INTEGRITY_LEVEL_LOW;
148
info.allow_ui_operation = false;
149
info.in_system_dir = true; // use system dir not to lock current directory
150
info.creation_flags = CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW;
153
const bool result = mozc::Process::SpawnProcessAs(
154
server_program(), arg, info, &tmp_pid);
155
pid = static_cast<size_t>(tmp_pid);
158
LOG(ERROR) << "Can't start process: " << ::GetLastError();
161
#elif defined(OS_MACOSX)
162
// Use launchd API instead of spawning process. It doesn't use
163
// server_program() at all.
164
const bool result = MacUtil::StartLaunchdServce(
165
"Converter", reinterpret_cast<pid_t *>(&pid));
167
LOG(ERROR) << "Can't start process";
171
const bool result = mozc::Process::SpawnProcess(server_program(),
175
LOG(ERROR) << "Can't start process: " << strerror(result);
180
// maybe another process will launch mozc_server at the same time.
181
if (session->PingServer()) {
182
VLOG(1) << "Another process has launched the server";
187
// Wait until mozc_server becomes ready to process requests
188
if (listener_is_available) {
189
const int ret = listener.WaitEventOrProcess(kServerWaitTimeout, pid);
191
case NamedEventListener::TIMEOUT:
192
LOG(WARNING) << "seems that Google Japanese Input Converter is not "
193
<< "ready within " << kServerWaitTimeout << " msec";
195
case NamedEventListener::EVENT_SIGNALED:
196
VLOG(1) << "Google Japanese Input Converter is launched successfully "
197
<< "within " << kServerWaitTimeout << " msec";
199
case NamedEventListener::PROCESS_SIGNALED:
200
LOG(ERROR) << "Mozc server is terminated";
201
// Mozc may be terminated because another client launches mozc_server
202
if (session->PingServer()) {
208
// maybe another process is trying to launch mozc_server.
209
LOG(ERROR) << "cannot make NamedEventListener ";
210
Util::Sleep(kRetryIntervalForServer);
213
// Try to connect mozc_server just in case.
214
for (int trial = 0; trial < kTrial; ++trial) {
215
if (session->PingServer()) {
218
Util::Sleep(kRetryIntervalForServer);
221
LOG(ERROR) << "Google Japanese Input Converter cannot be launched";
226
bool StartServerHandler::ForceTerminateServer(const string &name) {
227
return IPCClient::TerminateServer(name);
230
bool StartServerHandler::WaitServer(uint32 pid) {
231
const int kTimeout = 10000;
232
return Process::WaitProcess(static_cast<size_t>(pid), kTimeout);
235
void StartServerHandler::OnFatal(
236
StartServerHandlerInterface::ServerErrorType type) {
237
LOG(ERROR) << "OnFatal is called: " << static_cast<int>(type);
241
case StartServerHandlerInterface::SERVER_TIMEOUT:
242
error_type = "server_timeout";
244
case StartServerHandlerInterface::SERVER_BROKEN_MESSAGE:
245
error_type = "server_broken_message";
247
case StartServerHandlerInterface::SERVER_VERSION_MISMATCH:
248
error_type = "server_version_mismatch";
250
case StartServerHandlerInterface::SERVER_SHUTDOWN:
251
error_type = "server_shutdown";
253
case StartServerHandlerInterface::SERVER_FATAL:
254
error_type = "server_fatal";
257
LOG(ERROR) << "Unknown error: " << type;
261
Process::LaunchErrorMessageDialog(error_type);