Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(806)

Unified Diff: chrome/browser/chromeos/input_method/ibus_controller_impl.cc

Issue 10159004: Extends DBusThreadManager to connect ibus-bus. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Apply comment. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/chromeos/input_method/ibus_controller_impl.h ('k') | chromeos/dbus/dbus_thread_manager.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chromeos/input_method/ibus_controller_impl.cc
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_impl.cc b/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
index 10a354a9e7c5bb725a9d1c61288aaa4b0ce4fbb1..788ded4a49e2406990efc9277e847b8d946bfc8c 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
+++ b/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
@@ -12,12 +12,19 @@
#include <stack>
#include <utility>
+#include "base/bind.h"
+#include "base/environment.h"
+#include "base/files/file_path_watcher.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/rand_util.h"
#include "base/stringprintf.h"
#include "base/string_split.h"
#include "chrome/browser/chromeos/input_method/input_method_config.h"
#include "chrome/browser/chromeos/input_method/input_method_property.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "content/public/browser/browser_thread.h"
// TODO(nona): Remove libibus dependency from this file. Then, write unit tests
// for all functions in this file. crbug.com/26334
@@ -357,13 +364,107 @@ std::string PrintPropList(IBusPropList *prop_list, int tree_level) {
return stream.str();
}
+class IBusAddressWatcher {
+ public:
+ class IBusAddressFileWatcherDelegate
+ : public base::files::FilePathWatcher::Delegate {
+ public:
+ IBusAddressFileWatcherDelegate(
+ const std::string& ibus_address,
+ IBusControllerImpl* controller,
+ IBusAddressWatcher* watcher)
+ : ibus_address_(ibus_address),
+ controller_(controller),
+ watcher_(watcher) {
+ DCHECK(watcher);
+ DCHECK(!ibus_address.empty());
+ }
+
+ virtual ~IBusAddressFileWatcherDelegate() {}
+
+ virtual void OnFilePathChanged(const FilePath& file_path) OVERRIDE {
+ if (!watcher_->IsWatching())
+ return;
+ bool success = content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &IBusControllerImpl::IBusDaemonInitializationDone,
+ controller_,
+ ibus_address_));
+ DCHECK(success);
+ watcher_->StopSoon();
+ }
+
+ private:
+ // The ibus-daemon address.
+ const std::string ibus_address_;
+ IBusControllerImpl* controller_;
+ IBusAddressWatcher* watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(IBusAddressFileWatcherDelegate);
+ };
+
+ static void Start(const std::string& ibus_address,
+ IBusControllerImpl* controller) {
+ IBusAddressWatcher* instance = IBusAddressWatcher::Get();
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string address_file_path;
+ // TODO(nona): move reading environment variables to UI thread.
+ env->GetVar("IBUS_ADDRESS_FILE", &address_file_path);
+ DCHECK(!address_file_path.empty());
+
+ if (instance->IsWatching())
+ instance->StopNow();
+ instance->watcher_ = new base::files::FilePathWatcher;
+
+ // The |delegate| is owned by watcher.
+ IBusAddressFileWatcherDelegate* delegate =
+ new IBusAddressFileWatcherDelegate(ibus_address, controller, instance);
+ bool result = instance->watcher_->Watch(FilePath(address_file_path),
+ delegate);
+ DCHECK(result);
+ }
+
+ void StopNow() {
+ delete watcher_;
+ watcher_ = NULL;
+ }
+
+ void StopSoon() {
+ if (!watcher_)
+ return;
+ MessageLoop::current()->DeleteSoon(FROM_HERE, watcher_);
+ watcher_ = NULL;
+ }
+
+ bool IsWatching() const {
+ return watcher_ != NULL;
+ }
+
+ private:
+ static IBusAddressWatcher* Get() {
+ static IBusAddressWatcher* instance = new IBusAddressWatcher;
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+ return instance;
+ }
+
+ // Singleton
+ IBusAddressWatcher()
+ : watcher_(NULL) {}
+ base::files::FilePathWatcher* watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(IBusAddressWatcher);
+};
+
} // namespace
IBusControllerImpl::IBusControllerImpl()
: ibus_(NULL),
ibus_config_(NULL),
- should_launch_daemon_(false),
- process_handle_(base::kNullProcessHandle) {
+ process_handle_(base::kNullProcessHandle),
+ ibus_daemon_status_(IBUS_DAEMON_STOP),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
IBusControllerImpl::~IBusControllerImpl() {
@@ -405,10 +506,13 @@ IBusControllerImpl::~IBusControllerImpl() {
bool IBusControllerImpl::Start() {
MaybeInitializeIBusBus();
- should_launch_daemon_ = true;
if (IBusConnectionsAreAlive())
return true;
- return MaybeLaunchIBusDaemon();
+ if (ibus_daemon_status_ == IBUS_DAEMON_STOP ||
+ ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN) {
+ return StartIBusDaemon();
+ }
+ return true;
}
void IBusControllerImpl::Reset() {
@@ -422,6 +526,13 @@ void IBusControllerImpl::Reset() {
}
bool IBusControllerImpl::Stop() {
+ if (ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN ||
+ ibus_daemon_status_ == IBUS_DAEMON_STOP) {
+ return true;
+ }
+
+ ibus_daemon_status_ = IBUS_DAEMON_SHUTTING_DOWN;
+ // TODO(nona): Shutdown ibus-bus connection.
if (IBusConnectionsAreAlive()) {
// Ask IBus to exit *asynchronously*.
ibus_bus_exit_async(ibus_,
@@ -436,21 +547,20 @@ bool IBusControllerImpl::Stop() {
g_object_unref(ibus_config_);
ibus_config_ = NULL;
}
- } else if (process_handle_ != base::kNullProcessHandle) {
+ } else {
base::KillProcess(process_handle_, -1, false /* wait */);
DVLOG(1) << "Killing ibus-daemon. PID="
<< base::GetProcId(process_handle_);
- } else {
- // The daemon hasn't been started yet.
}
-
process_handle_ = base::kNullProcessHandle;
- should_launch_daemon_ = false;
return true;
}
bool IBusControllerImpl::ChangeInputMethod(const std::string& id) {
- DCHECK(should_launch_daemon_);
+ if (ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN ||
+ ibus_daemon_status_ == IBUS_DAEMON_STOP) {
+ return false;
+ }
// Sanity checks.
DCHECK(!InputMethodUtil::IsKeyboardLayout(id));
@@ -572,7 +682,7 @@ void IBusControllerImpl::CancelHandwriting(int n_strokes) {
#endif
bool IBusControllerImpl::IBusConnectionsAreAlive() {
- return (process_handle_ != base::kNullProcessHandle) &&
+ return (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) &&
ibus_ && ibus_bus_is_connected(ibus_) && ibus_config_;
}
@@ -892,27 +1002,48 @@ void IBusControllerImpl::UpdateProperty(IBusPanelService* panel,
}
}
-bool IBusControllerImpl::MaybeLaunchIBusDaemon() {
- static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
-
- if (process_handle_ != base::kNullProcessHandle) {
+bool IBusControllerImpl::StartIBusDaemon() {
+ if (ibus_daemon_status_ == IBUS_DAEMON_INITIALIZING ||
+ ibus_daemon_status_ == IBUS_DAEMON_RUNNING) {
DVLOG(1) << "MaybeLaunchIBusDaemon: ibus-daemon is already running.";
return false;
}
- if (!should_launch_daemon_)
- return false;
+ ibus_daemon_status_ = IBUS_DAEMON_INITIALIZING;
+ ibus_daemon_address_ = base::StringPrintf(
+ "unix:abstract=ibus-%d",
+ base::RandInt(0, std::numeric_limits<int>::max()));
+
+ // Set up ibus-daemon address file watcher before launching ibus-daemon,
+ // because if watcher starts after ibus-daemon, we may miss the ibus
+ // connection initialization.
+ bool success = content::BrowserThread::PostTaskAndReply(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&IBusAddressWatcher::Start,
+ ibus_daemon_address_,
+ base::Unretained(this)),
+ base::Bind(&IBusControllerImpl::LaunchIBusDaemon,
+ weak_ptr_factory_.GetWeakPtr(),
+ ibus_daemon_address_));
+ DCHECK(success);
+ return true;
+}
+
+void IBusControllerImpl::LaunchIBusDaemon(const std::string& ibus_address) {
+ DCHECK_EQ(base::kNullProcessHandle, process_handle_);
+ static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
// TODO(zork): Send output to /var/log/ibus.log
const std::string ibus_daemon_command_line =
- base::StringPrintf("%s --panel=disable --cache=none --restart --replace",
- kIBusDaemonPath);
+ base::StringPrintf("%s --panel=disable --cache=none --restart --replace"
+ " --address=%s",
+ kIBusDaemonPath,
+ ibus_address.c_str());
if (!LaunchProcess(ibus_daemon_command_line,
&process_handle_,
reinterpret_cast<GChildWatchFunc>(OnIBusDaemonExit))) {
DVLOG(1) << "Failed to launch " << ibus_daemon_command_line;
- return false;
}
- return true;
}
bool IBusControllerImpl::LaunchProcess(const std::string& command_line,
@@ -940,6 +1071,22 @@ bool IBusControllerImpl::LaunchProcess(const std::string& command_line,
}
// static
+void IBusControllerImpl::IBusDaemonInitializationDone(
+ IBusControllerImpl* controller,
+ const std::string& ibus_address) {
+ if (controller->ibus_daemon_address_ != ibus_address)
+ return;
+
+ if (controller->ibus_daemon_status_ != IBUS_DAEMON_INITIALIZING) {
+ // Stop() or OnIBusDaemonExit() has already been called.
+ return;
+ }
+ chromeos::DBusThreadManager::Get()->InitIBusBus(ibus_address);
+ controller->ibus_daemon_status_ = IBUS_DAEMON_RUNNING;
+ VLOG(1) << "The ibus-daemon initialization is done.";
+}
+
+// static
void IBusControllerImpl::SetInputMethodConfigCallback(GObject* source_object,
GAsyncResult* res,
gpointer user_data) {
@@ -967,12 +1114,31 @@ void IBusControllerImpl::SetInputMethodConfigCallback(GObject* source_object,
void IBusControllerImpl::OnIBusDaemonExit(GPid pid,
gint status,
IBusControllerImpl* controller) {
- if (controller->process_handle_ != base::kNullProcessHandle &&
- base::GetProcId(controller->process_handle_) == pid) {
- controller->process_handle_ = base::kNullProcessHandle;
+ if (controller->process_handle_ != base::kNullProcessHandle) {
+ if (base::GetProcId(controller->process_handle_) == pid) {
+ // ibus-daemon crashed.
+ // TODO(nona): Shutdown ibus-bus connection.
+ controller->process_handle_ = base::kNullProcessHandle;
+ } else {
+ // This condition is as follows.
+ // 1. Called Stop (process_handle_ becomes null)
+ // 2. Called LaunchProcess (process_handle_ becomes new instance)
+ // 3. Callbacked OnIBusDaemonExit for old instance and reach here.
+ // In this case, we should not reset process_handle_ as null, and do not
+ // re-launch ibus-daemon.
+ return;
+ }
+ }
+
+ const IBusDaemonStatus on_exit_state = controller->ibus_daemon_status_;
+ controller->ibus_daemon_status_ = IBUS_DAEMON_STOP;
+ if (on_exit_state == IBUS_DAEMON_SHUTTING_DOWN) {
+ // Normal exitting, so do nothing.
+ return;
}
- // Restart the daemon if needed.
- controller->MaybeLaunchIBusDaemon();
+
+ LOG(ERROR) << "The ibus-daemon crashed. Re-launching...";
+ controller->StartIBusDaemon();
}
#endif // defined(HAVE_IBUS)
« no previous file with comments | « chrome/browser/chromeos/input_method/ibus_controller_impl.h ('k') | chromeos/dbus/dbus_thread_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698