| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/ime/ibus_daemon_controller.h" | 5 #include "chromeos/ime/ibus_daemon_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/environment.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/files/file_path_watcher.h" | 9 #include "base/files/file_path_watcher.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/observer_list.h" | 12 #include "base/observer_list.h" |
| 13 #include "base/process/launch.h" | |
| 14 #include "base/process/process_handle.h" | |
| 15 #include "base/rand_util.h" | |
| 16 #include "base/strings/string_util.h" | |
| 17 #include "base/strings/stringprintf.h" | |
| 18 #include "base/threading/thread_checker.h" | |
| 19 #include "chromeos/dbus/dbus_thread_manager.h" | 13 #include "chromeos/dbus/dbus_thread_manager.h" |
| 20 | 14 |
| 21 namespace chromeos { | 15 namespace chromeos { |
| 22 | 16 |
| 23 namespace { | 17 namespace { |
| 24 | 18 |
| 25 IBusDaemonController* g_ibus_daemon_controller = NULL; | 19 IBusDaemonController* g_ibus_daemon_controller = NULL; |
| 26 base::FilePathWatcher* g_file_path_watcher = NULL; | 20 base::FilePathWatcher* g_file_path_watcher = NULL; |
| 27 | 21 |
| 28 // Called when the ibus-daemon address file is modified. | 22 // Called when the ibus-daemon address file is modified. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 52 g_file_path_watcher = new base::FilePathWatcher; | 46 g_file_path_watcher = new base::FilePathWatcher; |
| 53 bool result = g_file_path_watcher->Watch( | 47 bool result = g_file_path_watcher->Watch( |
| 54 base::FilePath::FromUTF8Unsafe(address_file_path), | 48 base::FilePath::FromUTF8Unsafe(address_file_path), |
| 55 false, // do not watch child directory. | 49 false, // do not watch child directory. |
| 56 base::Bind(&OnFilePathChanged, | 50 base::Bind(&OnFilePathChanged, |
| 57 ui_task_runner, | 51 ui_task_runner, |
| 58 closure)); | 52 closure)); |
| 59 DCHECK(result); | 53 DCHECK(result); |
| 60 } | 54 } |
| 61 | 55 |
| 62 // The implementation of IBusDaemonController. | |
| 63 class IBusDaemonControllerImpl : public IBusDaemonController { | |
| 64 public: | |
| 65 // Represents current ibus-daemon status. | |
| 66 enum IBusDaemonStatus { | |
| 67 IBUS_DAEMON_INITIALIZING, | |
| 68 IBUS_DAEMON_RUNNING, | |
| 69 IBUS_DAEMON_SHUTTING_DOWN, | |
| 70 IBUS_DAEMON_STOP, | |
| 71 }; | |
| 72 | |
| 73 IBusDaemonControllerImpl( | |
| 74 const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, | |
| 75 const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) | |
| 76 : process_handle_(base::kNullProcessHandle), | |
| 77 ibus_daemon_status_(IBUS_DAEMON_STOP), | |
| 78 ui_task_runner_(ui_task_runner), | |
| 79 file_task_runner_(file_task_runner), | |
| 80 weak_ptr_factory_(this) { | |
| 81 } | |
| 82 | |
| 83 virtual ~IBusDaemonControllerImpl() {} | |
| 84 | |
| 85 // IBusDaemonController override: | |
| 86 virtual void AddObserver(Observer* observer) OVERRIDE { | |
| 87 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 88 observers_.AddObserver(observer); | |
| 89 } | |
| 90 | |
| 91 // IBusDaemonController override: | |
| 92 virtual void RemoveObserver(Observer* observer) OVERRIDE { | |
| 93 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 94 observers_.RemoveObserver(observer); | |
| 95 } | |
| 96 | |
| 97 // IBusDaemonController override: | |
| 98 virtual bool Start() OVERRIDE { | |
| 99 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 100 if (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) | |
| 101 return true; | |
| 102 if (ibus_daemon_status_ == IBUS_DAEMON_STOP || | |
| 103 ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN) { | |
| 104 return StartIBusDaemon(); | |
| 105 } | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 // IBusDaemonController override: | |
| 110 virtual bool Stop() OVERRIDE { | |
| 111 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 112 NOTREACHED() << "Termination of ibus-daemon is not supported" | |
| 113 << "http://crosbug.com/27051"; | |
| 114 return false; | |
| 115 } | |
| 116 | |
| 117 private: | |
| 118 // Starts ibus-daemon service. | |
| 119 bool StartIBusDaemon() { | |
| 120 if (ibus_daemon_status_ == IBUS_DAEMON_INITIALIZING || | |
| 121 ibus_daemon_status_ == IBUS_DAEMON_RUNNING) { | |
| 122 DVLOG(1) << "MaybeLaunchIBusDaemon: ibus-daemon is already running."; | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 ibus_daemon_status_ = IBUS_DAEMON_INITIALIZING; | |
| 127 ibus_daemon_address_ = base::StringPrintf( | |
| 128 "unix:abstract=ibus-%d", | |
| 129 base::RandInt(0, std::numeric_limits<int>::max())); | |
| 130 | |
| 131 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 132 std::string address_file_path; | |
| 133 env->GetVar("IBUS_ADDRESS_FILE", &address_file_path); | |
| 134 DCHECK(!address_file_path.empty()); | |
| 135 | |
| 136 // Set up ibus-daemon address file watcher before launching ibus-daemon, | |
| 137 // because if watcher starts after ibus-daemon, we may miss the ibus | |
| 138 // connection initialization. | |
| 139 bool success = file_task_runner_->PostTaskAndReply( | |
| 140 FROM_HERE, | |
| 141 base::Bind(&StartWatch, | |
| 142 address_file_path, | |
| 143 base::Bind(&IBusDaemonControllerImpl::FilePathChanged, | |
| 144 weak_ptr_factory_.GetWeakPtr(), | |
| 145 ibus_daemon_address_), | |
| 146 ui_task_runner_), | |
| 147 base::Bind(&IBusDaemonControllerImpl::LaunchIBusDaemon, | |
| 148 weak_ptr_factory_.GetWeakPtr(), | |
| 149 ibus_daemon_address_)); | |
| 150 DCHECK(success); | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 // Launhes actual ibus-daemon process. | |
| 155 void LaunchIBusDaemon(const std::string& ibus_address) { | |
| 156 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 157 DCHECK_EQ(base::kNullProcessHandle, process_handle_); | |
| 158 static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; | |
| 159 // TODO(zork): Send output to /var/log/ibus.log | |
| 160 std::vector<std::string> ibus_daemon_command_line; | |
| 161 ibus_daemon_command_line.push_back(kIBusDaemonPath); | |
| 162 ibus_daemon_command_line.push_back("--panel=disable"); | |
| 163 ibus_daemon_command_line.push_back("--cache=none"); | |
| 164 ibus_daemon_command_line.push_back("--restart"); | |
| 165 ibus_daemon_command_line.push_back("--replace"); | |
| 166 ibus_daemon_command_line.push_back("--address=" + ibus_address); | |
| 167 | |
| 168 if (!base::LaunchProcess(ibus_daemon_command_line, | |
| 169 base::LaunchOptions(), | |
| 170 &process_handle_)) { | |
| 171 LOG(WARNING) << "Could not launch: " | |
| 172 << JoinString(ibus_daemon_command_line, " "); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Called by FilePathWatcher when the ibus-daemon address file is changed. | |
| 177 // This function will be called on FILE thread. | |
| 178 void FilePathChanged(const std::string& ibus_address) { | |
| 179 ui_task_runner_->PostTask( | |
| 180 FROM_HERE, | |
| 181 base::Bind(&IBusDaemonControllerImpl::IBusDaemonInitializationDone, | |
| 182 weak_ptr_factory_.GetWeakPtr(), | |
| 183 ibus_address)); | |
| 184 } | |
| 185 | |
| 186 // Called by FilePathChaged function, this function should be called on UI | |
| 187 // thread. | |
| 188 void IBusDaemonInitializationDone(const std::string& ibus_address) { | |
| 189 if (ibus_daemon_address_ != ibus_address) | |
| 190 return; | |
| 191 | |
| 192 if (ibus_daemon_status_ != IBUS_DAEMON_INITIALIZING) { | |
| 193 // Stop() or OnIBusDaemonExit() has already been called. | |
| 194 return; | |
| 195 } | |
| 196 | |
| 197 DBusThreadManager::Get()->InitIBusBus( | |
| 198 ibus_address, | |
| 199 base::Bind(&IBusDaemonControllerImpl::OnIBusDaemonDisconnected, | |
| 200 weak_ptr_factory_.GetWeakPtr(), | |
| 201 base::GetProcId(process_handle_))); | |
| 202 ibus_daemon_status_ = IBUS_DAEMON_RUNNING; | |
| 203 FOR_EACH_OBSERVER(Observer, observers_, OnConnected()); | |
| 204 | |
| 205 VLOG(1) << "The ibus-daemon initialization is done."; | |
| 206 } | |
| 207 | |
| 208 // Called when the connection with ibus-daemon is disconnected. | |
| 209 void OnIBusDaemonDisconnected(base::ProcessId pid) { | |
| 210 if (!chromeos::DBusThreadManager::Get()) | |
| 211 return; // Expected disconnection at shutting down. do nothing. | |
| 212 | |
| 213 if (process_handle_ != base::kNullProcessHandle) { | |
| 214 if (base::GetProcId(process_handle_) == pid) { | |
| 215 // ibus-daemon crashed. | |
| 216 // TODO(nona): Shutdown ibus-bus connection. | |
| 217 process_handle_ = base::kNullProcessHandle; | |
| 218 } else { | |
| 219 // This condition is as follows. | |
| 220 // 1. Called Stop (process_handle_ becomes null) | |
| 221 // 2. Called LaunchProcess (process_handle_ becomes new instance) | |
| 222 // 3. Callbacked OnIBusDaemonExit for old instance and reach here. | |
| 223 // In this case, we should not reset process_handle_ as null, and do not | |
| 224 // re-launch ibus-daemon. | |
| 225 return; | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 const IBusDaemonStatus on_exit_state = ibus_daemon_status_; | |
| 230 ibus_daemon_status_ = IBUS_DAEMON_STOP; | |
| 231 FOR_EACH_OBSERVER(Observer, observers_, OnDisconnected()); | |
| 232 | |
| 233 if (on_exit_state == IBUS_DAEMON_SHUTTING_DOWN) | |
| 234 return; // Normal exitting, so do nothing. | |
| 235 | |
| 236 LOG(ERROR) << "The ibus-daemon crashed. Re-launching..."; | |
| 237 StartIBusDaemon(); | |
| 238 } | |
| 239 | |
| 240 // The current ibus_daemon address. This value is assigned at the launching | |
| 241 // ibus-daemon and used in bus connection initialization. | |
| 242 std::string ibus_daemon_address_; | |
| 243 | |
| 244 // The process handle of the IBus daemon. kNullProcessHandle if it's not | |
| 245 // running. | |
| 246 base::ProcessHandle process_handle_; | |
| 247 | |
| 248 // Represents ibus-daemon's status. | |
| 249 IBusDaemonStatus ibus_daemon_status_; | |
| 250 | |
| 251 // The task runner of UI thread. | |
| 252 scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; | |
| 253 | |
| 254 // The task runner of FILE thread. | |
| 255 scoped_refptr<base::SequencedTaskRunner> file_task_runner_; | |
| 256 | |
| 257 ObserverList<Observer> observers_; | |
| 258 base::ThreadChecker thread_checker_; | |
| 259 | |
| 260 // Used for making callbacks for PostTask. | |
| 261 base::WeakPtrFactory<IBusDaemonControllerImpl> weak_ptr_factory_; | |
| 262 | |
| 263 DISALLOW_COPY_AND_ASSIGN(IBusDaemonControllerImpl); | |
| 264 }; | |
| 265 | |
| 266 // An implementation of IBusDaemonController without ibus-daemon interaction. | 56 // An implementation of IBusDaemonController without ibus-daemon interaction. |
| 267 // Currently this class is used only on linux desktop. | 57 // Currently this class is used only on linux desktop. |
| 268 // TODO(nona): Remove IBusDaemonControlelr this once crbug.com/171351 is fixed. | 58 // TODO(nona): Remove IBusDaemonControlelr this once crbug.com/171351 is fixed. |
| 269 class IBusDaemonControllerDaemonlessImpl : public IBusDaemonController { | 59 class IBusDaemonControllerDaemonlessImpl : public IBusDaemonController { |
| 270 public: | 60 public: |
| 271 IBusDaemonControllerDaemonlessImpl() | 61 IBusDaemonControllerDaemonlessImpl() |
| 272 : is_started_(false) {} | 62 : is_started_(false) {} |
| 273 virtual ~IBusDaemonControllerDaemonlessImpl() {} | 63 virtual ~IBusDaemonControllerDaemonlessImpl() {} |
| 274 | 64 |
| 275 // IBusDaemonController overrides: | 65 // IBusDaemonController overrides: |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 delete g_ibus_daemon_controller; | 133 delete g_ibus_daemon_controller; |
| 344 g_ibus_daemon_controller = NULL; | 134 g_ibus_daemon_controller = NULL; |
| 345 } | 135 } |
| 346 | 136 |
| 347 // static | 137 // static |
| 348 IBusDaemonController* IBusDaemonController::GetInstance() { | 138 IBusDaemonController* IBusDaemonController::GetInstance() { |
| 349 return g_ibus_daemon_controller; | 139 return g_ibus_daemon_controller; |
| 350 } | 140 } |
| 351 | 141 |
| 352 } // namespace chromeos | 142 } // namespace chromeos |
| OLD | NEW |