Updates for vm_cicerone for migration compatibility

vm_cicerone is the new daemon in Chrome OS that is the result of splitting
vm_concierge into 2 pieces. cicerone will do all of the communication
with the container. As we cannot update Chrome and Chrome OS in
lockstep, we need to stage the changes properly for this.

This change adds vm_cicerone to the 2 D-Bus services that it will be
invoking in Chrome. It also updates concierge_client so that it listens
for the ContainerStarted signal from both concierge and cicerone since
cicerone is not able to send a concierge signal.

Once cicerone is complete then we will update Chrome to use cicerone
instead of concierge where relevant and remove the crosvm user from the
2 D-Bus configs and remove the usage of the concierge ContainerStarted
signal.

Bug: 842845
Test: Verified terminal startup, open url and vm app updates
Change-Id: I22f7d2dfd62330c53824452fc659a663f1375b0f
Reviewed-on: https://chromium-review.googlesource.com/1069772
Commit-Queue: Jeffrey Kardatzke <[email protected]>
Reviewed-by: Dan Erat <[email protected]>
Reviewed-by: Ryo Hashimoto <[email protected]>
Reviewed-by: Nicholas Verne <[email protected]>
Cr-Commit-Position: refs/heads/master@{#563330}
diff --git a/ash/dbus/org.chromium.UrlHandlerService.conf b/ash/dbus/org.chromium.UrlHandlerService.conf
index 79d1073..b012ac5 100644
--- a/ash/dbus/org.chromium.UrlHandlerService.conf
+++ b/ash/dbus/org.chromium.UrlHandlerService.conf
@@ -9,10 +9,17 @@
   <policy user="chronos">
     <allow own="org.chromium.UrlHandlerService"/>
   </policy>
+  <!-- TODO(jkardatzke): Remove crosvm when Chrome migrates to cicerone -->
   <policy user="crosvm">
     <!-- methods allowed -->
     <allow send_destination="org.chromium.UrlHandlerService"
            send_interface="org.chromium.UrlHandlerServiceInterface"
            send_member="OpenUrl"/>
   </policy>
+  <policy user="vm_cicerone">
+    <!-- methods allowed -->
+    <allow send_destination="org.chromium.UrlHandlerService"
+           send_interface="org.chromium.UrlHandlerServiceInterface"
+           send_member="OpenUrl"/>
+  </policy>
 </busconfig>
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 2822cc49..4e7df62 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -27,6 +27,7 @@
     "//chrome:strings",
     "//chrome/app/resources:platform_locale_settings",
     "//chrome/app/theme:theme_resources",
+    "//chromeos:cicerone_proto",
     "//chromeos:concierge_proto",
     "//chromeos:power_manager_proto",
     "//chromeos:vm_applications_apps_proto",
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index c4bc663d..982e104b 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -38,6 +38,10 @@
 constexpr base::FilePath::CharType kHomeDirectory[] =
     FILE_PATH_LITERAL("/home");
 
+chromeos::CiceroneClient* GetCiceroneClient() {
+  return chromeos::DBusThreadManager::Get()->GetCiceroneClient();
+}
+
 chromeos::ConciergeClient* GetConciergeClient() {
   return chromeos::DBusThreadManager::Get()->GetConciergeClient();
 }
@@ -373,6 +377,20 @@
   NOTREACHED();
 }
 
+void OnConciergeServiceAvailable(
+    CrostiniManager::StartConciergeCallback callback,
+    bool success) {
+  if (!success) {
+    LOG(ERROR) << "Concierge service did not become available";
+    std::move(callback).Run(success);
+    return;
+  }
+  VLOG(1) << "Concierge service announced availability";
+  VLOG(1) << "Waiting for Cicerone to announce availability.";
+
+  GetCiceroneClient()->WaitForServiceToBeAvailable(std::move(callback));
+}
+
 }  // namespace
 
 // static
@@ -381,9 +399,10 @@
 }
 
 CrostiniManager::CrostiniManager() : weak_ptr_factory_(this) {
-  // ConciergeClient and its observer_list_ will be destroyed together.
+  // Cicerone/ConciergeClient and its observer_list_ will be destroyed together.
   // We add, but don't need to remove the observer. (Doing so would force a
-  // "destroyed before" dependency on the owner of ConciergeClient).
+  // "destroyed before" dependency on the owner of Cicerone/ConciergeClient).
+  GetCiceroneClient()->AddObserver(this);
   GetConciergeClient()->AddObserver(this);
 }
 
@@ -414,7 +433,8 @@
   VLOG(1) << "Concierge service started";
   VLOG(1) << "Waiting for Concierge to announce availability.";
 
-  GetConciergeClient()->WaitForServiceToBeAvailable(std::move(callback));
+  GetConciergeClient()->WaitForServiceToBeAvailable(
+      base::BindOnce(&OnConciergeServiceAvailable, std::move(callback)));
 }
 
 void CrostiniManager::StopConcierge(StopConciergeCallback callback) {
@@ -623,7 +643,8 @@
     std::move(callback).Run(ConciergeClientResult::CLIENT_ERROR);
     return;
   }
-  if (!GetConciergeClient()->IsContainerStartedSignalConnected()) {
+  if (!GetConciergeClient()->IsContainerStartedSignalConnected() ||
+      !GetCiceroneClient()->IsContainerStartedSignalConnected()) {
     LOG(ERROR) << "Async call to StartContainer can't complete when signal "
                   "is not connected.";
     std::move(callback).Run(ConciergeClientResult::CLIENT_ERROR);
@@ -913,6 +934,22 @@
   start_container_callbacks_.erase(range.first, range.second);
 }
 
+void CrostiniManager::OnContainerStarted(
+    const vm_tools::cicerone::ContainerStartedSignal& signal) {
+  // Find the callbacks to call, then erase them from the map.
+  std::string owner_id = signal.owner_id();
+  // TODO(jkardatzke): remove this check once Cicerone always fills in owner_id.
+  if (owner_id.empty()) {
+    owner_id = CryptohomeIdForProfile(ProfileManager::GetPrimaryUserProfile());
+  }
+  auto range = start_container_callbacks_.equal_range(
+      std::make_tuple(owner_id, signal.vm_name(), signal.container_name()));
+  for (auto it = range.first; it != range.second; ++it) {
+    std::move(it->second).Run(ConciergeClientResult::SUCCESS);
+  }
+  start_container_callbacks_.erase(range.first, range.second);
+}
+
 void CrostiniManager::OnLaunchContainerApplication(
     LaunchContainerApplicationCallback callback,
     base::Optional<vm_tools::concierge::LaunchContainerApplicationResponse>
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index a8a68430..feb4269 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -12,6 +12,8 @@
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "chromeos/dbus/cicerone/cicerone_service.pb.h"
+#include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge/service.pb.h"
 #include "chromeos/dbus/concierge_client.h"
 
@@ -43,10 +45,14 @@
   std::string content;
 };
 
-// CrostiniManager is a singleton which is used to check arguments for the
-// ConciergeClient. ConciergeClient is dedicated to communication with the
-// Concierge service and should remain as thin as possible.
-class CrostiniManager : public chromeos::ConciergeClient::Observer {
+// CrostiniManager is a singleton which is used to check arguments for
+// ConciergeClient and CiceroneClient. ConciergeClient is dedicated to
+// communication with the Concierge service, CiceroneClient is dedicated to
+// communication with the Cicerone service and both should remain as thin as
+// possible. The existence of Cicerone is abstracted behind this class and
+// only the Concierge name is exposed outside of here.
+class CrostiniManager : public chromeos::ConciergeClient::Observer,
+                        public chromeos::CiceroneClient::Observer {
  public:
   using ConciergeClientCallback =
       base::OnceCallback<void(ConciergeClientResult result)>;
@@ -210,6 +216,10 @@
   void OnContainerStartupFailed(
       const vm_tools::concierge::ContainerStartedSignal& signal) override;
 
+  // CiceroneClient::Observer:
+  void OnContainerStarted(
+      const vm_tools::cicerone::ContainerStartedSignal& signal) override;
+
   void RemoveCrostini(Profile* profile,
                       std::string vm_name,
                       std::string container_name,
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 2d2d4bac..0eb8181 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_cicerone_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -93,11 +94,14 @@
   }
 
   CrostiniManagerTest()
-      : fake_concierge_client_(new chromeos::FakeConciergeClient()),
+      : fake_cicerone_client_(new chromeos::FakeCiceroneClient()),
+        fake_concierge_client_(new chromeos::FakeConciergeClient()),
         scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::UI),
         test_browser_thread_bundle_(
             content::TestBrowserThreadBundle::REAL_IO_THREAD) {
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetCiceroneClient(
+        base::WrapUnique(fake_cicerone_client_));
     chromeos::DBusThreadManager::GetSetterForTesting()->SetConciergeClient(
         base::WrapUnique(fake_concierge_client_));
     chromeos::DBusThreadManager::Initialize();
@@ -119,7 +123,10 @@
   base::RunLoop* run_loop() { return run_loop_.get(); }
   Profile* profile() { return profile_.get(); }
 
+  // Owned by chromeos::DBusThreadManager
+  chromeos::FakeCiceroneClient* fake_cicerone_client_;
   chromeos::FakeConciergeClient* fake_concierge_client_;
+
   std::unique_ptr<base::RunLoop>
       run_loop_;  // run_loop_ must be created on the UI thread.
   std::unique_ptr<TestingProfile> profile_;
@@ -304,7 +311,7 @@
   run_loop()->Run();
 }
 
-TEST_F(CrostiniManagerTest, StartContainerSignalNotConnectedError) {
+TEST_F(CrostiniManagerTest, StartContainerSignalConciergeNotConnectedError) {
   fake_concierge_client_->set_container_started_signal_connected(false);
   CrostiniManager::GetInstance()->StartContainer(
       kVmName, kContainerName, kContainerUserName, kCryptohomeId,
@@ -313,6 +320,15 @@
   run_loop()->Run();
 }
 
+TEST_F(CrostiniManagerTest, StartContainerSignalCiceroneNotConnectedError) {
+  fake_cicerone_client_->set_container_started_signal_connected(false);
+  CrostiniManager::GetInstance()->StartContainer(
+      kVmName, kContainerName, kContainerUserName, kCryptohomeId,
+      base::BindOnce(&CrostiniManagerTest::StartContainerClientErrorCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()));
+  run_loop()->Run();
+}
+
 TEST_F(CrostiniManagerTest, StartContainerSuccess) {
   CrostiniManager::GetInstance()->StartContainer(
       kVmName, kContainerName, kContainerUserName, kCryptohomeId,
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index b5f23578..f46d9c2 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -25,6 +25,7 @@
     ":attestation_proto",
     ":authpolicy_proto",
     ":biod_proto",
+    ":cicerone_proto",
     ":concierge_proto",
     ":cryptohome_proto",
     ":login_manager_proto",
@@ -160,6 +161,8 @@
     "dbus/blocking_method_caller.h",
     "dbus/cec_service_client.cc",
     "dbus/cec_service_client.h",
+    "dbus/cicerone_client.cc",
+    "dbus/cicerone_client.h",
     "dbus/concierge_client.cc",
     "dbus/concierge_client.h",
     "dbus/cras_audio_client.cc",
@@ -193,6 +196,8 @@
     "dbus/fake_auth_policy_client.h",
     "dbus/fake_cec_service_client.cc",
     "dbus/fake_cec_service_client.h",
+    "dbus/fake_cicerone_client.cc",
+    "dbus/fake_cicerone_client.h",
     "dbus/fake_concierge_client.cc",
     "dbus/fake_concierge_client.h",
     "dbus/fake_cras_audio_client.cc",
@@ -939,6 +944,14 @@
   proto_out_dir = "chromeos/account_manager"
 }
 
+proto_library("cicerone_proto") {
+  sources = [
+    "//third_party/cros_system_api/dbus/vm_cicerone/cicerone_service.proto",
+  ]
+
+  proto_out_dir = "chromeos/dbus/cicerone"
+}
+
 proto_library("concierge_proto") {
   sources = [
     "//third_party/cros_system_api/dbus/vm_concierge/service.proto",
diff --git a/chromeos/dbus/cicerone_client.cc b/chromeos/dbus/cicerone_client.cc
new file mode 100644
index 0000000..c8c22ef9
--- /dev/null
+++ b/chromeos/dbus/cicerone_client.cc
@@ -0,0 +1,168 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/cicerone_client.h"
+
+#include "base/bind.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+#include "third_party/cros_system_api/dbus/vm_cicerone/dbus-constants.h"
+
+namespace chromeos {
+
+class CiceroneClientImpl : public CiceroneClient {
+ public:
+  CiceroneClientImpl() : weak_ptr_factory_(this) {}
+
+  ~CiceroneClientImpl() override = default;
+
+  void AddObserver(Observer* observer) override {
+    observer_list_.AddObserver(observer);
+  }
+
+  void RemoveObserver(Observer* observer) override {
+    observer_list_.RemoveObserver(observer);
+  }
+
+  bool IsContainerStartedSignalConnected() override {
+    return is_container_started_signal_connected_;
+  }
+
+  void LaunchContainerApplication(
+      const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
+          callback) override {
+    dbus::MethodCall method_call(
+        vm_tools::cicerone::kVmCiceroneInterface,
+        vm_tools::cicerone::kLaunchContainerApplicationMethod);
+    dbus::MessageWriter writer(&method_call);
+
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      LOG(ERROR)
+          << "Failed to encode LaunchContainerApplicationRequest protobuf";
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+
+    cicerone_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
+        base::BindOnce(
+            &CiceroneClientImpl::OnDBusProtoResponse<
+                vm_tools::cicerone::LaunchContainerApplicationResponse>,
+            weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void GetContainerAppIcons(
+      const vm_tools::cicerone::ContainerAppIconRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse> callback)
+      override {
+    dbus::MethodCall method_call(
+        vm_tools::cicerone::kVmCiceroneInterface,
+        vm_tools::cicerone::kGetContainerAppIconMethod);
+    dbus::MessageWriter writer(&method_call);
+
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      LOG(ERROR) << "Failed to encode ContainerAppIonRequest protobuf";
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+
+    cicerone_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
+        base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
+                           vm_tools::cicerone::ContainerAppIconResponse>,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)
+      override {
+    cicerone_proxy_->WaitForServiceToBeAvailable(std::move(callback));
+  }
+
+ protected:
+  void Init(dbus::Bus* bus) override {
+    cicerone_proxy_ = bus->GetObjectProxy(
+        vm_tools::cicerone::kVmCiceroneServiceName,
+        dbus::ObjectPath(vm_tools::cicerone::kVmCiceroneServicePath));
+    if (!cicerone_proxy_) {
+      LOG(ERROR) << "Unable to get dbus proxy for "
+                 << vm_tools::cicerone::kVmCiceroneServiceName;
+    }
+    cicerone_proxy_->ConnectToSignal(
+        vm_tools::cicerone::kVmCiceroneInterface,
+        vm_tools::cicerone::kContainerStartedSignal,
+        base::BindRepeating(&CiceroneClientImpl::OnContainerStartedSignal,
+                            weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+
+ private:
+  template <typename ResponseProto>
+  void OnDBusProtoResponse(DBusMethodCallback<ResponseProto> callback,
+                           dbus::Response* dbus_response) {
+    if (!dbus_response) {
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    ResponseProto reponse_proto;
+    dbus::MessageReader reader(dbus_response);
+    if (!reader.PopArrayOfBytesAsProto(&reponse_proto)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Response.";
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+    std::move(callback).Run(std::move(reponse_proto));
+  }
+
+  void OnContainerStartedSignal(dbus::Signal* signal) {
+    vm_tools::cicerone::ContainerStartedSignal container_started_signal;
+    dbus::MessageReader reader(signal);
+    if (!reader.PopArrayOfBytesAsProto(&container_started_signal)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Signal";
+      return;
+    }
+    for (auto& observer : observer_list_) {
+      observer.OnContainerStarted(container_started_signal);
+    }
+  }
+
+  void OnSignalConnected(const std::string& interface_name,
+                         const std::string& signal_name,
+                         bool is_connected) {
+    if (!is_connected) {
+      LOG(ERROR)
+          << "Failed to connect to Signal. Async StartContainer will not work";
+    }
+    DCHECK_EQ(interface_name, vm_tools::cicerone::kVmCiceroneInterface);
+    DCHECK_EQ(signal_name, vm_tools::cicerone::kContainerStartedSignal);
+    is_container_started_signal_connected_ = is_connected;
+  }
+
+  dbus::ObjectProxy* cicerone_proxy_ = nullptr;
+
+  base::ObserverList<Observer> observer_list_;
+
+  bool is_container_started_signal_connected_ = false;
+
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<CiceroneClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CiceroneClientImpl);
+};
+
+CiceroneClient::CiceroneClient() = default;
+
+CiceroneClient::~CiceroneClient() = default;
+
+std::unique_ptr<CiceroneClient> CiceroneClient::Create() {
+  return std::make_unique<CiceroneClientImpl>();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/cicerone_client.h b/chromeos/dbus/cicerone_client.h
new file mode 100644
index 0000000..9fff65b
--- /dev/null
+++ b/chromeos/dbus/cicerone_client.h
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_CICERONE_CLIENT_H_
+#define CHROMEOS_DBUS_CICERONE_CLIENT_H_
+
+#include <memory>
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/cicerone/cicerone_service.pb.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+
+// CiceroneClient is used to communicate with Cicerone, which is used to
+// communicate with containers running inside VMs.
+class CHROMEOS_EXPORT CiceroneClient : public DBusClient {
+ public:
+  class Observer {
+   public:
+    // OnContainerStarted is signaled by Cicerone after the long-running
+    // container startup process has been completed and the container is ready.
+    virtual void OnContainerStarted(
+        const vm_tools::cicerone::ContainerStartedSignal& signal) = 0;
+
+   protected:
+    virtual ~Observer() = default;
+  };
+
+  ~CiceroneClient() override;
+
+  // Adds an observer.
+  virtual void AddObserver(Observer* observer) = 0;
+
+  // Removes an observer if added.
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // IsContainerStartedSignalConnected must return true before StartContainer
+  // is called.
+  virtual bool IsContainerStartedSignalConnected() = 0;
+
+  // Launches an application inside a running Container.
+  // |callback| is called after the method call finishes.
+  virtual void LaunchContainerApplication(
+      const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
+          callback) = 0;
+
+  // Gets application icons from inside a Container.
+  // |callback| is called after the method call finishes.
+  virtual void GetContainerAppIcons(
+      const vm_tools::cicerone::ContainerAppIconRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse>
+          callback) = 0;
+
+  // Registers |callback| to run when the Cicerone service becomes available.
+  // If the service is already available, or if connecting to the name-owner-
+  // changed signal fails, |callback| will be run once asynchronously.
+  // Otherwise, |callback| will be run once in the future after the service
+  // becomes available.
+  virtual void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) = 0;
+
+  // Creates an instance of CiceroneClient.
+  static std::unique_ptr<CiceroneClient> Create();
+
+ protected:
+  // Create() should be used instead.
+  CiceroneClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CiceroneClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_CICERONE_CLIENT_H_
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 6e974c9..44a499fa 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -10,6 +10,7 @@
 #include "chromeos/dbus/arc_obb_mounter_client.h"
 #include "chromeos/dbus/arc_oemcrypto_client.h"
 #include "chromeos/dbus/auth_policy_client.h"
+#include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
@@ -21,6 +22,7 @@
 #include "chromeos/dbus/fake_arc_obb_mounter_client.h"
 #include "chromeos/dbus/fake_arc_oemcrypto_client.h"
 #include "chromeos/dbus/fake_auth_policy_client.h"
+#include "chromeos/dbus/fake_cicerone_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "chromeos/dbus/fake_debug_daemon_client.h"
 #include "chromeos/dbus/fake_easy_unlock_client.h"
@@ -72,6 +74,11 @@
                        : FAKE_DBUS_CLIENT_IMPLEMENTATION));
 
   if (use_real_clients)
+    cicerone_client_ = CiceroneClient::Create();
+  else
+    cicerone_client_ = std::make_unique<FakeCiceroneClient>();
+
+  if (use_real_clients)
     concierge_client_.reset(ConciergeClient::Create());
   else
     concierge_client_.reset(new FakeConciergeClient);
@@ -126,6 +133,7 @@
   arc_obb_mounter_client_->Init(system_bus);
   arc_oemcrypto_client_->Init(system_bus);
   auth_policy_client_->Init(system_bus);
+  cicerone_client_->Init(system_bus);
   concierge_client_->Init(system_bus);
   cros_disks_client_->Init(system_bus);
   debug_daemon_client_->Init(system_bus);
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index f51ff2b7..8593da79 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -21,6 +21,7 @@
 class ArcObbMounterClient;
 class ArcOemCryptoClient;
 class AuthPolicyClient;
+class CiceroneClient;
 class ConciergeClient;
 class CrosDisksClient;
 class DebugDaemonClient;
@@ -52,6 +53,7 @@
   std::unique_ptr<ArcObbMounterClient> arc_obb_mounter_client_;
   std::unique_ptr<ArcOemCryptoClient> arc_oemcrypto_client_;
   std::unique_ptr<AuthPolicyClient> auth_policy_client_;
+  std::unique_ptr<CiceroneClient> cicerone_client_;
   std::unique_ptr<ConciergeClient> concierge_client_;
   std::unique_ptr<CrosDisksClient> cros_disks_client_;
   std::unique_ptr<DebugDaemonClient> debug_daemon_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index fa171e2..8ae5e69 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -18,6 +18,7 @@
 #include "chromeos/dbus/auth_policy_client.h"
 #include "chromeos/dbus/biod/biod_client.h"
 #include "chromeos/dbus/cec_service_client.h"
+#include "chromeos/dbus/cicerone_client.h"
 #include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/cros_disks_client.h"
@@ -148,6 +149,10 @@
   return clients_common_->cec_service_client_.get();
 }
 
+CiceroneClient* DBusThreadManager::GetCiceroneClient() {
+  return clients_browser_ ? clients_browser_->cicerone_client_.get() : nullptr;
+}
+
 ConciergeClient* DBusThreadManager::GetConciergeClient() {
   return clients_browser_ ? clients_browser_->concierge_client_.get() : nullptr;
 }
@@ -363,6 +368,12 @@
   DBusThreadManager::Get()->clients_common_->biod_client_ = std::move(client);
 }
 
+void DBusThreadManagerSetter::SetCiceroneClient(
+    std::unique_ptr<CiceroneClient> client) {
+  DBusThreadManager::Get()->clients_browser_->cicerone_client_ =
+      std::move(client);
+}
+
 void DBusThreadManagerSetter::SetConciergeClient(
     std::unique_ptr<ConciergeClient> client) {
   DBusThreadManager::Get()->clients_browser_->concierge_client_ =
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 7f48c33..43897f4e 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -31,6 +31,7 @@
 class AuthPolicyClient;
 class BiodClient;
 class CecServiceClient;
+class CiceroneClient;
 class ConciergeClient;
 class CrasAudioClient;
 class CrosDisksClient;
@@ -138,6 +139,7 @@
   AuthPolicyClient* GetAuthPolicyClient();
   BiodClient* GetBiodClient();
   CecServiceClient* GetCecServiceClient();
+  CiceroneClient* GetCiceroneClient();
   ConciergeClient* GetConciergeClient();
   CrasAudioClient* GetCrasAudioClient();
   CrosDisksClient* GetCrosDisksClient();
@@ -201,6 +203,7 @@
 
   void SetAuthPolicyClient(std::unique_ptr<AuthPolicyClient> client);
   void SetBiodClient(std::unique_ptr<BiodClient> client);
+  void SetCiceroneClient(std::unique_ptr<CiceroneClient> client);
   void SetConciergeClient(std::unique_ptr<ConciergeClient> client);
   void SetCrasAudioClient(std::unique_ptr<CrasAudioClient> client);
   void SetCrosDisksClient(std::unique_ptr<CrosDisksClient> client);
diff --git a/chromeos/dbus/dbus_thread_manager_unittest.cc b/chromeos/dbus/dbus_thread_manager_unittest.cc
index f1d05d6b..cd3e822 100644
--- a/chromeos/dbus/dbus_thread_manager_unittest.cc
+++ b/chromeos/dbus/dbus_thread_manager_unittest.cc
@@ -23,6 +23,7 @@
   EXPECT_TRUE(manager->GetArcMidisClient());
   EXPECT_TRUE(manager->GetArcObbMounterClient());
   EXPECT_TRUE(manager->GetArcOemCryptoClient());
+  EXPECT_TRUE(manager->GetCiceroneClient());
   EXPECT_TRUE(manager->GetConciergeClient());
   EXPECT_TRUE(manager->GetCrasAudioClient());
   EXPECT_TRUE(manager->GetCrosDisksClient());
@@ -78,6 +79,7 @@
   EXPECT_TRUE(manager->GetArcMidisClient());
   EXPECT_TRUE(manager->GetArcObbMounterClient());
   EXPECT_TRUE(manager->GetArcOemCryptoClient());
+  EXPECT_TRUE(manager->GetCiceroneClient());
   EXPECT_TRUE(manager->GetConciergeClient());
   EXPECT_TRUE(manager->GetCrosDisksClient());
   EXPECT_TRUE(manager->GetDebugDaemonClient());
@@ -116,6 +118,7 @@
   EXPECT_FALSE(manager->GetArcMidisClient());
   EXPECT_FALSE(manager->GetArcObbMounterClient());
   EXPECT_FALSE(manager->GetArcOemCryptoClient());
+  EXPECT_FALSE(manager->GetCiceroneClient());
   EXPECT_FALSE(manager->GetConciergeClient());
   EXPECT_FALSE(manager->GetCrosDisksClient());
   EXPECT_FALSE(manager->GetDebugDaemonClient());
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
new file mode 100644
index 0000000..8943e9b
--- /dev/null
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/fake_cicerone_client.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace chromeos {
+
+FakeCiceroneClient::FakeCiceroneClient() {}
+FakeCiceroneClient::~FakeCiceroneClient() = default;
+
+void FakeCiceroneClient::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void FakeCiceroneClient::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+bool FakeCiceroneClient::IsContainerStartedSignalConnected() {
+  return is_container_started_signal_connected_;
+}
+
+void FakeCiceroneClient::LaunchContainerApplication(
+    const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
+    DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
+        callback) {
+  vm_tools::cicerone::LaunchContainerApplicationResponse response;
+  response.set_success(true);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
+}
+
+void FakeCiceroneClient::GetContainerAppIcons(
+    const vm_tools::cicerone::ContainerAppIconRequest& request,
+    DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse> callback) {
+  vm_tools::cicerone::ContainerAppIconResponse response;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
+}
+
+void FakeCiceroneClient::WaitForServiceToBeAvailable(
+    dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), true));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
new file mode 100644
index 0000000..c2e69fc1
--- /dev/null
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_FAKE_CICERONE_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_CICERONE_CLIENT_H_
+
+#include "base/observer_list.h"
+#include "chromeos/dbus/cicerone_client.h"
+
+namespace chromeos {
+
+// FakeCiceroneClient is a fake implementation of CiceroneClient used for
+// testing.
+class CHROMEOS_EXPORT FakeCiceroneClient : public CiceroneClient {
+ public:
+  FakeCiceroneClient();
+  ~FakeCiceroneClient() override;
+
+  // CiceroneClient overrides:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+
+  // IsContainerStartedSignalConnected must return true before StartContainer
+  // is called.
+  bool IsContainerStartedSignalConnected() override;
+
+  // Fake version of the method that launches an application inside a running
+  // Container. |callback| is called after the method call finishes.
+  void LaunchContainerApplication(
+      const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
+          callback) override;
+
+  // Fake version of the method that gets application icons from inside a
+  // Container. |callback| is called after the method call finishes.
+  void GetContainerAppIcons(
+      const vm_tools::cicerone::ContainerAppIconRequest& request,
+      DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse> callback)
+      override;
+
+  // Fake version of the method that waits for the Cicerone service to be
+  // availble.  |callback| is called after the method call finishes.
+  void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
+
+  // Set ContainerStartedSignalConnected state
+  void set_container_started_signal_connected(bool connected) {
+    is_container_started_signal_connected_ = connected;
+  }
+
+ protected:
+  void Init(dbus::Bus* bus) override {}
+
+ private:
+  bool is_container_started_signal_connected_ = true;
+  base::ObserverList<Observer> observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCiceroneClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_CICERONE_CLIENT_H_
diff --git a/chromeos/dbus/services/org.chromium.VmApplicationsService.conf b/chromeos/dbus/services/org.chromium.VmApplicationsService.conf
index 98f6022..441bf83 100644
--- a/chromeos/dbus/services/org.chromium.VmApplicationsService.conf
+++ b/chromeos/dbus/services/org.chromium.VmApplicationsService.conf
@@ -11,9 +11,14 @@
     <allow own="org.chromium.VmApplicationsService"/>
   </policy>
 
+  <!-- TODO(jkardatzke):Remove the one for crosvm once we migrate Chrome to cicerone -->
   <!-- The concierge service runs as crosvm -->
   <policy user="crosvm">
     <allow send_destination="org.chromium.VmApplicationsService"
            send_interface="org.chromium.VmApplicationsService"/>
   </policy>
+  <policy user="vm_cicerone">
+    <allow send_destination="org.chromium.VmApplicationsService"
+           send_interface="org.chromium.VmApplicationsService"/>
+  </policy>
 </busconfig>