|  | // Copyright 2018 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/ash/dbus/component_updater_service_provider.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/logging.h" | 
|  | #include "chrome/browser/component_updater/cros_component_installer_chromeos.h" | 
|  | #include "content/public/browser/browser_task_traits.h" | 
|  | #include "content/public/browser/browser_thread.h" | 
|  | #include "dbus/bus.h" | 
|  | #include "dbus/message.h" | 
|  | #include "third_party/cros_system_api/dbus/service_constants.h" | 
|  |  | 
|  | namespace ash { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const char kErrorInvalidArgs[] = "org.freedesktop.DBus.Error.InvalidArgs"; | 
|  | const char kErrorInternalError[] = "org.freedesktop.DBus.Error.InternalError"; | 
|  |  | 
|  | std::string ErrorToString( | 
|  | component_updater::CrOSComponentManager::Error error) { | 
|  | switch (error) { | 
|  | case component_updater::CrOSComponentManager::Error::NONE: | 
|  | return "NONE"; | 
|  | case component_updater::CrOSComponentManager::Error::UNKNOWN_COMPONENT: | 
|  | return "UNKNOWN_COMPONENT"; | 
|  | case component_updater::CrOSComponentManager::Error::INSTALL_FAILURE: | 
|  | return "INSTALL_FAILURE"; | 
|  | case component_updater::CrOSComponentManager::Error::MOUNT_FAILURE: | 
|  | return "MOUNT_FAILURE"; | 
|  | case component_updater::CrOSComponentManager::Error:: | 
|  | COMPATIBILITY_CHECK_FAILED: | 
|  | return "COMPATIBILITY_CHECK_FAILED"; | 
|  | case component_updater::CrOSComponentManager::Error::NOT_FOUND: | 
|  | return "NOT_FOUND"; | 
|  | case component_updater::CrOSComponentManager::Error::UPDATE_IN_PROGRESS: | 
|  | return "UPDATE_IN_PROGRESS"; | 
|  | case component_updater::CrOSComponentManager::Error::ERROR_MAX: | 
|  | return "ERROR_MAX"; | 
|  | } | 
|  | return "Unknown error code"; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ComponentUpdaterServiceProvider::ComponentUpdaterServiceProvider( | 
|  | component_updater::CrOSComponentManager* cros_component_manager) { | 
|  | DCHECK(cros_component_manager); | 
|  |  | 
|  | cros_component_manager_ = cros_component_manager; | 
|  | cros_component_manager_->SetDelegate(this); | 
|  | } | 
|  |  | 
|  | ComponentUpdaterServiceProvider::~ComponentUpdaterServiceProvider() { | 
|  | cros_component_manager_->SetDelegate(nullptr); | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::Start( | 
|  | scoped_refptr<dbus::ExportedObject> exported_object) { | 
|  | exported_object->ExportMethod( | 
|  | chromeos::kComponentUpdaterServiceInterface, | 
|  | chromeos::kComponentUpdaterServiceLoadComponentMethod, | 
|  | base::BindRepeating(&ComponentUpdaterServiceProvider::LoadComponent, | 
|  | weak_ptr_factory_.GetWeakPtr()), | 
|  | base::BindOnce(&ComponentUpdaterServiceProvider::OnExported, | 
|  | weak_ptr_factory_.GetWeakPtr())); | 
|  |  | 
|  | exported_object->ExportMethod( | 
|  | chromeos::kComponentUpdaterServiceInterface, | 
|  | chromeos::kComponentUpdaterServiceUnloadComponentMethod, | 
|  | base::BindRepeating(&ComponentUpdaterServiceProvider::UnloadComponent, | 
|  | weak_ptr_factory_.GetWeakPtr()), | 
|  | base::BindOnce(&ComponentUpdaterServiceProvider::OnExported, | 
|  | weak_ptr_factory_.GetWeakPtr())); | 
|  |  | 
|  | exported_object_ = exported_object; | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::EmitInstalledSignal( | 
|  | const std::string& component) { | 
|  | content::GetUIThreadTaskRunner({})->PostTask( | 
|  | FROM_HERE, | 
|  | base::BindOnce( | 
|  | &ComponentUpdaterServiceProvider::EmitInstalledSignalInternal, | 
|  | weak_ptr_factory_.GetWeakPtr(), component)); | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::OnExported( | 
|  | const std::string& interface_name, | 
|  | const std::string& method_name, | 
|  | bool success) { | 
|  | if (!success) { | 
|  | LOG(ERROR) << "Failed to export " << interface_name << "." << method_name; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::LoadComponent( | 
|  | dbus::MethodCall* method_call, | 
|  | dbus::ExportedObject::ResponseSender response_sender) { | 
|  | dbus::MessageReader reader(method_call); | 
|  | std::string component_name; | 
|  | // |mount| is an optional parameter, and by default is true. | 
|  | bool mount = true; | 
|  | if (reader.PopString(&component_name)) { | 
|  | // dbus::MessageReader::PopBool sets its out-param to false on failure. | 
|  | // Resets |mount| to its default value on failure. | 
|  | if (!reader.PopBool(&mount)) | 
|  | mount = true; | 
|  | cros_component_manager_->Load( | 
|  | component_name, | 
|  | mount | 
|  | ? component_updater::CrOSComponentManager::MountPolicy::kMount | 
|  | : component_updater::CrOSComponentManager::MountPolicy::kDontMount, | 
|  | component_updater::CrOSComponentManager::UpdatePolicy::kDontForce, | 
|  | base::BindOnce(&ComponentUpdaterServiceProvider::OnLoadComponent, | 
|  | weak_ptr_factory_.GetWeakPtr(), method_call, | 
|  | std::move(response_sender))); | 
|  | } else { | 
|  | std::unique_ptr<dbus::ErrorResponse> error_response = | 
|  | dbus::ErrorResponse::FromMethodCall( | 
|  | method_call, kErrorInvalidArgs, | 
|  | "Need a string and a boolean parameter."); | 
|  | std::move(response_sender).Run(std::move(error_response)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::OnLoadComponent( | 
|  | dbus::MethodCall* method_call, | 
|  | dbus::ExportedObject::ResponseSender response_sender, | 
|  | component_updater::CrOSComponentManager::Error error, | 
|  | const base::FilePath& result) { | 
|  | if (error != component_updater::CrOSComponentManager::Error::NONE) { | 
|  | LOG(ERROR) << "Component updater Load API error: " << ErrorToString(error); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<dbus::Response> response = | 
|  | dbus::Response::FromMethodCall(method_call); | 
|  | dbus::MessageWriter writer(response.get()); | 
|  | writer.AppendString(result.value()); | 
|  | std::move(response_sender).Run(std::move(response)); | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::UnloadComponent( | 
|  | dbus::MethodCall* method_call, | 
|  | dbus::ExportedObject::ResponseSender response_sender) { | 
|  | dbus::MessageReader reader(method_call); | 
|  | std::string component_name; | 
|  | if (reader.PopString(&component_name)) { | 
|  | if (cros_component_manager_->Unload(component_name)) { | 
|  | std::move(response_sender) | 
|  | .Run(dbus::Response::FromMethodCall(method_call)); | 
|  | } else { | 
|  | std::move(response_sender) | 
|  | .Run(dbus::ErrorResponse::FromMethodCall( | 
|  | method_call, kErrorInternalError, "Failed to unload component")); | 
|  | } | 
|  | } else { | 
|  | std::move(response_sender) | 
|  | .Run(dbus::ErrorResponse::FromMethodCall( | 
|  | method_call, kErrorInvalidArgs, | 
|  | "Missing component name string argument.")); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ComponentUpdaterServiceProvider::EmitInstalledSignalInternal( | 
|  | const std::string& component) { | 
|  | DCHECK(exported_object_); | 
|  |  | 
|  | dbus::Signal signal( | 
|  | chromeos::kComponentUpdaterServiceInterface, | 
|  | chromeos::kComponentUpdaterServiceComponentInstalledSignal); | 
|  |  | 
|  | dbus::MessageWriter writer(&signal); | 
|  | writer.AppendString(component); | 
|  | exported_object_->SendSignal(&signal); | 
|  | } | 
|  |  | 
|  | }  // namespace ash |