12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/ime/ibus_daemon_controller.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/chromeos/chromeos_version.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/environment.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path_watcher.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/observer_list.h" 14a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h" 15a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/process_handle.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_checker.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IBusDaemonController* g_ibus_daemon_controller = NULL; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePathWatcher* g_file_path_watcher = NULL; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Called when the ibus-daemon address file is modified. 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void OnFilePathChanged( 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner> ui_task_runner, 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& closure, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& file_path, 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool failed) { 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (failed) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // Can't recover, do nothing. 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!g_file_path_watcher) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // Already discarded watch task. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner->PostTask(FROM_HERE, closure); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner->DeleteSoon(FROM_HERE, g_file_path_watcher); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_file_path_watcher = NULL; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Start watching |address_file_path|. If the target file is changed, |callback| 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is called on UI thread. This function should be called on FILE thread. 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartWatch( 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& address_file_path, 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::Closure& closure, 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Before start watching, discard on-going watching task. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete g_file_path_watcher; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_file_path_watcher = new base::FilePathWatcher; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool result = g_file_path_watcher->Watch( 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath::FromUTF8Unsafe(address_file_path), 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) false, // do not watch child directory. 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&OnFilePathChanged, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closure)); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(result); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The implementation of IBusDaemonController. 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class IBusDaemonControllerImpl : public IBusDaemonController { 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Represents current ibus-daemon status. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enum IBusDaemonStatus { 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBUS_DAEMON_INITIALIZING, 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBUS_DAEMON_RUNNING, 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBUS_DAEMON_SHUTTING_DOWN, 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBUS_DAEMON_STOP, 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBusDaemonControllerImpl( 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : process_handle_(base::kNullProcessHandle), 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_(IBUS_DAEMON_STOP), 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_(ui_task_runner), 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_task_runner_(file_task_runner), 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~IBusDaemonControllerImpl() {} 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusDaemonController override: 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AddObserver(Observer* observer) OVERRIDE { 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusDaemonController override: 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void RemoveObserver(Observer* observer) OVERRIDE { 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusDaemonController override: 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Start() OVERRIDE { 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ibus_daemon_status_ == IBUS_DAEMON_STOP || 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return StartIBusDaemon(); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusDaemonController override: 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Stop() OVERRIDE { 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED() << "Termination of ibus-daemon is not supported" 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "http://crosbug.com/27051"; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Starts ibus-daemon service. 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool StartIBusDaemon() { 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ibus_daemon_status_ == IBUS_DAEMON_INITIALIZING || 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_ == IBUS_DAEMON_RUNNING) { 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "MaybeLaunchIBusDaemon: ibus-daemon is already running."; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_ = IBUS_DAEMON_INITIALIZING; 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_address_ = base::StringPrintf( 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "unix:abstract=ibus-%d", 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::RandInt(0, std::numeric_limits<int>::max())); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string address_file_path; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) env->GetVar("IBUS_ADDRESS_FILE", &address_file_path); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!address_file_path.empty()); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set up ibus-daemon address file watcher before launching ibus-daemon, 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // because if watcher starts after ibus-daemon, we may miss the ibus 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // connection initialization. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success = file_task_runner_->PostTaskAndReply( 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&StartWatch, 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_file_path, 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&IBusDaemonControllerImpl::FilePathChanged, 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_address_), 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_), 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&IBusDaemonControllerImpl::LaunchIBusDaemon, 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_address_)); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(success); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Launhes actual ibus-daemon process. 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void LaunchIBusDaemon(const std::string& ibus_address) { 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(base::kNullProcessHandle, process_handle_); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(zork): Send output to /var/log/ibus.log 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<std::string> ibus_daemon_command_line; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back(kIBusDaemonPath); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back("--panel=disable"); 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back("--cache=none"); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back("--restart"); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back("--replace"); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_command_line.push_back("--address=" + ibus_address); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::LaunchProcess(ibus_daemon_command_line, 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::LaunchOptions(), 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &process_handle_)) { 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(WARNING) << "Could not launch: " 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << JoinString(ibus_daemon_command_line, " "); 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Called by FilePathWatcher when the ibus-daemon address file is changed. 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This function will be called on FILE thread. 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void FilePathChanged(const std::string& ibus_address) { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui_task_runner_->PostTask( 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&IBusDaemonControllerImpl::IBusDaemonInitializationDone, 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_address)); 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Called by FilePathChaged function, this function should be called on UI 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // thread. 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void IBusDaemonInitializationDone(const std::string& ibus_address) { 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ibus_daemon_address_ != ibus_address) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ibus_daemon_status_ != IBUS_DAEMON_INITIALIZING) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Stop() or OnIBusDaemonExit() has already been called. 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusThreadManager::Get()->InitIBusBus( 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_address, 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&IBusDaemonControllerImpl::OnIBusDaemonDisconnected, 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::GetProcId(process_handle_))); 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_ = IBUS_DAEMON_RUNNING; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnConnected()); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VLOG(1) << "The ibus-daemon initialization is done."; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Called when the connection with ibus-daemon is disconnected. 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnIBusDaemonDisconnected(base::ProcessId pid) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!chromeos::DBusThreadManager::Get()) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // Expected disconnection at shutting down. do nothing. 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (process_handle_ != base::kNullProcessHandle) { 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::GetProcId(process_handle_) == pid) { 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ibus-daemon crashed. 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(nona): Shutdown ibus-bus connection. 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) process_handle_ = base::kNullProcessHandle; 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This condition is as follows. 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1. Called Stop (process_handle_ becomes null) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 2. Called LaunchProcess (process_handle_ becomes new instance) 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 3. Callbacked OnIBusDaemonExit for old instance and reach here. 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // In this case, we should not reset process_handle_ as null, and do not 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // re-launch ibus-daemon. 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const IBusDaemonStatus on_exit_state = ibus_daemon_status_; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ibus_daemon_status_ = IBUS_DAEMON_STOP; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnDisconnected()); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (on_exit_state == IBUS_DAEMON_SHUTTING_DOWN) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; // Normal exitting, so do nothing. 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "The ibus-daemon crashed. Re-launching..."; 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) StartIBusDaemon(); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The current ibus_daemon address. This value is assigned at the launching 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ibus-daemon and used in bus connection initialization. 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string ibus_daemon_address_; 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The process handle of the IBus daemon. kNullProcessHandle if it's not 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // running. 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ProcessHandle process_handle_; 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Represents ibus-daemon's status. 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBusDaemonStatus ibus_daemon_status_; 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The task runner of UI thread. 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The task runner of FILE thread. 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> file_task_runner_; 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ObserverList<Observer> observers_; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ThreadChecker thread_checker_; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Used for making callbacks for PostTask. 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtrFactory<IBusDaemonControllerImpl> weak_ptr_factory_; 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(IBusDaemonControllerImpl); 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// An implementation of IBusDaemonController without ibus-daemon interaction. 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Currently this class is used only on linux desktop. 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(nona): Remove IBusDaemonControlelr this once crbug.com/171351 is fixed. 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class IBusDaemonControllerDaemonlessImpl : public IBusDaemonController { 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBusDaemonControllerDaemonlessImpl() 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : is_started_(false) {} 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~IBusDaemonControllerDaemonlessImpl() {} 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusDaemonController overrides: 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void AddObserver(Observer* observer) OVERRIDE { 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void RemoveObserver(Observer* observer) OVERRIDE { 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Start() OVERRIDE { 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_started_) 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IBusBus should be initialized but it is okay to pass "dummy address" as 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the bus address because the actual dbus implementation is stub if the 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Chrome OS is working on Linux desktop. This path is not used in 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // production at this moment, only for Chrome OS on Linux Desktop. 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(nona): Remove InitIBusBus oncer all legacy ime is migrated to IME 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // extension API. 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!base::chromeos::IsRunningOnChromeOS()); 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DBusThreadManager::Get()->InitIBusBus("dummy address", 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&base::DoNothing)); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_started_ = true; 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnConnected()); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool Stop() OVERRIDE { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_started_) 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_started_ = false; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnDisconnected()); 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ObserverList<Observer> observers_; 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_started_; 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(IBusDaemonControllerDaemonlessImpl); 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// IBusDaemonController 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IBusDaemonController::IBusDaemonController() { 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IBusDaemonController::~IBusDaemonController() { 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IBusDaemonController::Initialize( 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner, 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) { 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(g_ibus_daemon_controller == NULL) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Do not call Initialize function multiple times."; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (base::chromeos::IsRunningOnChromeOS()) { 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_ibus_daemon_controller = new IBusDaemonControllerImpl(ui_task_runner, 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) file_task_runner); 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_ibus_daemon_controller = new IBusDaemonControllerDaemonlessImpl(); 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IBusDaemonController::InitializeForTesting( 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IBusDaemonController* controller) { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(g_ibus_daemon_controller == NULL); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(controller); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_ibus_daemon_controller = controller; 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IBusDaemonController::Shutdown() { 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete g_ibus_daemon_controller; 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_ibus_daemon_controller = NULL; 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IBusDaemonController* IBusDaemonController::GetInstance() { 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return g_ibus_daemon_controller; 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace chromeos 360