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