blob: 5de9e5c10fd6d0852f00856479867633e2d32e1d [file] [log] [blame]
Ken Turneredb93932018-02-14 05:27:31 +11001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ml/daemon.h"
6
Andrew Moylanef116f92018-04-11 15:12:38 +10007#include <sysexits.h>
8
9#include <memory>
10#include <utility>
11
12#include <base/bind.h>
Andrew Moylanff6be512018-07-03 11:05:01 +100013#include <base/files/file_util.h>
Andrew Moylanef116f92018-04-11 15:12:38 +100014#include <base/memory/ref_counted.h>
15#include <chromeos/dbus/service_constants.h>
16#include <dbus/bus.h>
17#include <dbus/message.h>
Qijiang Fan7da812d2019-11-26 10:48:46 +090018#include <mojo/core/embedder/embedder.h>
Qijiang Fan3b917c72019-12-09 15:24:15 +090019#include <mojo/public/cpp/system/invitation.h>
Andrew Moylanff6be512018-07-03 11:05:01 +100020
21#include "ml/machine_learning_service_impl.h"
Andrew Moylanef116f92018-04-11 15:12:38 +100022
Ken Turneredb93932018-02-14 05:27:31 +110023namespace ml {
24
Andrew Moylanef116f92018-04-11 15:12:38 +100025Daemon::Daemon() : weak_ptr_factory_(this) {}
Ken Turneredb93932018-02-14 05:27:31 +110026
27Daemon::~Daemon() {}
28
29int Daemon::OnInit() {
Andrew Moylanef116f92018-04-11 15:12:38 +100030 int exit_code = DBusDaemon::OnInit();
31 if (exit_code != EX_OK)
32 return exit_code;
33
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100034 metrics_.StartCollectingProcessMetrics();
Qijiang Fan7da812d2019-11-26 10:48:46 +090035 mojo::core::Init();
36 ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
37 base::ThreadTaskRunnerHandle::Get(),
38 mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
Ken Turneredb93932018-02-14 05:27:31 +110039 InitDBus();
Andrew Moylanff6be512018-07-03 11:05:01 +100040
Ken Turneredb93932018-02-14 05:27:31 +110041 return 0;
42}
43
44void Daemon::InitDBus() {
Andrew Moylanef116f92018-04-11 15:12:38 +100045 // Get or create the ExportedObject for the ML service.
46 dbus::ExportedObject* const ml_service_exported_object =
Andrew Moylan49f50b32018-07-27 08:48:11 +100047 bus_->GetExportedObject(dbus::ObjectPath(kMachineLearningServicePath));
Andrew Moylanef116f92018-04-11 15:12:38 +100048 CHECK(ml_service_exported_object);
49
50 // Register a handler of the BootstrapMojoConnection method.
51 CHECK(ml_service_exported_object->ExportMethodAndBlock(
Andrew Moylan49f50b32018-07-27 08:48:11 +100052 kMachineLearningInterfaceName, kBootstrapMojoConnectionMethod,
Andrew Moylanef116f92018-04-11 15:12:38 +100053 base::Bind(&Daemon::BootstrapMojoConnection,
54 weak_ptr_factory_.GetWeakPtr())));
55
56 // Take ownership of the ML service.
Andrew Moylan49f50b32018-07-27 08:48:11 +100057 CHECK(bus_->RequestOwnershipAndBlock(kMachineLearningServiceName,
Andrew Moylanef116f92018-04-11 15:12:38 +100058 dbus::Bus::REQUIRE_PRIMARY));
Ken Turneredb93932018-02-14 05:27:31 +110059}
60
61void Daemon::BootstrapMojoConnection(
62 dbus::MethodCall* method_call,
63 dbus::ExportedObject::ResponseSender response_sender) {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100064 metrics_.RecordMojoConnectionEvent(
65 Metrics::MojoConnectionEvent::kBootstrapRequested);
Andrew Moylanff6be512018-07-03 11:05:01 +100066 if (machine_learning_service_) {
67 LOG(ERROR) << "MachineLearningService already instantiated";
68 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
69 method_call, DBUS_ERROR_FAILED, "Bootstrap already completed"));
70 return;
71 }
Andrew Moylanef116f92018-04-11 15:12:38 +100072
Andrew Moylanff6be512018-07-03 11:05:01 +100073 base::ScopedFD file_handle;
74 dbus::MessageReader reader(method_call);
Andrew Moylanef116f92018-04-11 15:12:38 +100075
Andrew Moylanff6be512018-07-03 11:05:01 +100076 if (!reader.PopFileDescriptor(&file_handle)) {
77 LOG(ERROR) << "Couldn't extract file descriptor from D-Bus call";
78 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
79 method_call, DBUS_ERROR_INVALID_ARGS, "Expected file descriptor"));
80 return;
81 }
82
83 if (!file_handle.is_valid()) {
84 LOG(ERROR) << "ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
85 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
86 method_call, DBUS_ERROR_INVALID_ARGS,
87 "Invalid (empty) file descriptor"));
88 return;
89 }
90
91 if (!base::SetCloseOnExec(file_handle.get())) {
92 PLOG(ERROR) << "Failed setting FD_CLOEXEC on file descriptor";
93 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
94 method_call, DBUS_ERROR_FAILED,
95 "Failed setting FD_CLOEXEC on file descriptor"));
96 return;
97 }
98
99 // Connect to mojo in the requesting process.
Qijiang Fan3b917c72019-12-09 15:24:15 +0900100 mojo::IncomingInvitation invitation =
101 mojo::IncomingInvitation::Accept(mojo::PlatformChannelEndpoint(
102 mojo::PlatformHandle(std::move(file_handle))));
Andrew Moylanff6be512018-07-03 11:05:01 +1000103
104 // Bind primordial message pipe to a MachineLearningService implementation.
hscham3f45fcc2019-12-25 16:54:54 +0900105 machine_learning_service_ = std::make_unique<MachineLearningServiceImpl>(
Qijiang Fan3b917c72019-12-09 15:24:15 +0900106 invitation.ExtractMessagePipe(kBootstrapMojoConnectionChannelToken),
Andrew Moylanff6be512018-07-03 11:05:01 +1000107 base::Bind(&Daemon::OnConnectionError, base::Unretained(this)));
108
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000109 metrics_.RecordMojoConnectionEvent(
110 Metrics::MojoConnectionEvent::kBootstrapSucceeded);
111
Andrew Moylanff6be512018-07-03 11:05:01 +1000112 // Send success response.
113 response_sender.Run(dbus::Response::FromMethodCall(method_call));
114}
115
116void Daemon::OnConnectionError() {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000117 metrics_.RecordMojoConnectionEvent(
118 Metrics::MojoConnectionEvent::kConnectionError);
Andrew Moylanff6be512018-07-03 11:05:01 +1000119 // Die upon Mojo error. Reconnection can occur when the daemon is restarted.
120 // (A future Mojo API may enable Mojo re-bootstrap without a process restart.)
121 Quit();
Ken Turneredb93932018-02-14 05:27:31 +1100122}
123
124} // namespace ml