blob: e01a41fa0719ac057c6c0916a91ae670aa88c1f9 [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>
14#include <base/memory/ptr_util.h>
Andrew Moylanef116f92018-04-11 15:12:38 +100015#include <base/memory/ref_counted.h>
16#include <chromeos/dbus/service_constants.h>
17#include <dbus/bus.h>
18#include <dbus/message.h>
Andrew Moylanff6be512018-07-03 11:05:01 +100019#include <mojo/edk/embedder/embedder.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 Moylanff6be512018-07-03 11:05:01 +100025namespace {
26
Andrew Moylanff6be512018-07-03 11:05:01 +100027void InitMojo() {
28 mojo::edk::Init();
Hidehiko Abe8ab64a62018-09-19 00:04:39 +090029 mojo::edk::InitIPCSupport(base::ThreadTaskRunnerHandle::Get());
Andrew Moylanff6be512018-07-03 11:05:01 +100030}
31
32} // namespace
33
Andrew Moylanef116f92018-04-11 15:12:38 +100034Daemon::Daemon() : weak_ptr_factory_(this) {}
Ken Turneredb93932018-02-14 05:27:31 +110035
36Daemon::~Daemon() {}
37
38int Daemon::OnInit() {
Andrew Moylanef116f92018-04-11 15:12:38 +100039 int exit_code = DBusDaemon::OnInit();
40 if (exit_code != EX_OK)
41 return exit_code;
42
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100043 metrics_.StartCollectingProcessMetrics();
Andrew Moylanff6be512018-07-03 11:05:01 +100044 InitMojo();
Ken Turneredb93932018-02-14 05:27:31 +110045 InitDBus();
Andrew Moylanff6be512018-07-03 11:05:01 +100046
Ken Turneredb93932018-02-14 05:27:31 +110047 return 0;
48}
49
50void Daemon::InitDBus() {
Andrew Moylanef116f92018-04-11 15:12:38 +100051 // Get or create the ExportedObject for the ML service.
52 dbus::ExportedObject* const ml_service_exported_object =
Andrew Moylan49f50b32018-07-27 08:48:11 +100053 bus_->GetExportedObject(dbus::ObjectPath(kMachineLearningServicePath));
Andrew Moylanef116f92018-04-11 15:12:38 +100054 CHECK(ml_service_exported_object);
55
56 // Register a handler of the BootstrapMojoConnection method.
57 CHECK(ml_service_exported_object->ExportMethodAndBlock(
Andrew Moylan49f50b32018-07-27 08:48:11 +100058 kMachineLearningInterfaceName, kBootstrapMojoConnectionMethod,
Andrew Moylanef116f92018-04-11 15:12:38 +100059 base::Bind(&Daemon::BootstrapMojoConnection,
60 weak_ptr_factory_.GetWeakPtr())));
61
62 // Take ownership of the ML service.
Andrew Moylan49f50b32018-07-27 08:48:11 +100063 CHECK(bus_->RequestOwnershipAndBlock(kMachineLearningServiceName,
Andrew Moylanef116f92018-04-11 15:12:38 +100064 dbus::Bus::REQUIRE_PRIMARY));
Ken Turneredb93932018-02-14 05:27:31 +110065}
66
67void Daemon::BootstrapMojoConnection(
68 dbus::MethodCall* method_call,
69 dbus::ExportedObject::ResponseSender response_sender) {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100070 metrics_.RecordMojoConnectionEvent(
71 Metrics::MojoConnectionEvent::kBootstrapRequested);
Andrew Moylanff6be512018-07-03 11:05:01 +100072 if (machine_learning_service_) {
73 LOG(ERROR) << "MachineLearningService already instantiated";
74 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
75 method_call, DBUS_ERROR_FAILED, "Bootstrap already completed"));
76 return;
77 }
Andrew Moylanef116f92018-04-11 15:12:38 +100078
Andrew Moylanff6be512018-07-03 11:05:01 +100079 base::ScopedFD file_handle;
80 dbus::MessageReader reader(method_call);
Andrew Moylanef116f92018-04-11 15:12:38 +100081
Andrew Moylanff6be512018-07-03 11:05:01 +100082 if (!reader.PopFileDescriptor(&file_handle)) {
83 LOG(ERROR) << "Couldn't extract file descriptor from D-Bus call";
84 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
85 method_call, DBUS_ERROR_INVALID_ARGS, "Expected file descriptor"));
86 return;
87 }
88
89 if (!file_handle.is_valid()) {
90 LOG(ERROR) << "ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
91 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
92 method_call, DBUS_ERROR_INVALID_ARGS,
93 "Invalid (empty) file descriptor"));
94 return;
95 }
96
97 if (!base::SetCloseOnExec(file_handle.get())) {
98 PLOG(ERROR) << "Failed setting FD_CLOEXEC on file descriptor";
99 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
100 method_call, DBUS_ERROR_FAILED,
101 "Failed setting FD_CLOEXEC on file descriptor"));
102 return;
103 }
104
105 // Connect to mojo in the requesting process.
106 mojo::edk::SetParentPipeHandle(mojo::edk::ScopedPlatformHandle(
107 mojo::edk::PlatformHandle(file_handle.release())));
108
109 // Bind primordial message pipe to a MachineLearningService implementation.
110 machine_learning_service_ = base::MakeUnique<MachineLearningServiceImpl>(
111 mojo::edk::CreateChildMessagePipe(kBootstrapMojoConnectionChannelToken),
112 base::Bind(&Daemon::OnConnectionError, base::Unretained(this)));
113
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000114 metrics_.RecordMojoConnectionEvent(
115 Metrics::MojoConnectionEvent::kBootstrapSucceeded);
116
Andrew Moylanff6be512018-07-03 11:05:01 +1000117 // Send success response.
118 response_sender.Run(dbus::Response::FromMethodCall(method_call));
119}
120
121void Daemon::OnConnectionError() {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000122 metrics_.RecordMojoConnectionEvent(
123 Metrics::MojoConnectionEvent::kConnectionError);
Andrew Moylanff6be512018-07-03 11:05:01 +1000124 // Die upon Mojo error. Reconnection can occur when the daemon is restarted.
125 // (A future Mojo API may enable Mojo re-bootstrap without a process restart.)
126 Quit();
Ken Turneredb93932018-02-14 05:27:31 +1100127}
128
129} // namespace ml