blob: 600e5fb68597008990a33c535bfa31fd9fbc553d [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>
20#include <mojo/edk/embedder/process_delegate.h>
21
22#include "ml/machine_learning_service_impl.h"
Andrew Moylanef116f92018-04-11 15:12:38 +100023
Ken Turneredb93932018-02-14 05:27:31 +110024namespace ml {
25
Andrew Moylanff6be512018-07-03 11:05:01 +100026namespace {
27
28// A ProcessDelegate that does nothing upon IPC system shutdown.
29class DoNothingProcessDelegate : public mojo::edk::ProcessDelegate {
30 public:
31 void OnShutdownComplete() override {}
32};
33
34void InitMojo() {
35 mojo::edk::Init();
36 static DoNothingProcessDelegate process_delegate;
37 mojo::edk::InitIPCSupport(&process_delegate,
38 base::ThreadTaskRunnerHandle::Get());
39}
40
41} // namespace
42
Andrew Moylanef116f92018-04-11 15:12:38 +100043Daemon::Daemon() : weak_ptr_factory_(this) {}
Ken Turneredb93932018-02-14 05:27:31 +110044
45Daemon::~Daemon() {}
46
47int Daemon::OnInit() {
Andrew Moylanef116f92018-04-11 15:12:38 +100048 int exit_code = DBusDaemon::OnInit();
49 if (exit_code != EX_OK)
50 return exit_code;
51
Andrew Moylanff6be512018-07-03 11:05:01 +100052 InitMojo();
Ken Turneredb93932018-02-14 05:27:31 +110053 InitDBus();
Andrew Moylanff6be512018-07-03 11:05:01 +100054
Ken Turneredb93932018-02-14 05:27:31 +110055 return 0;
56}
57
58void Daemon::InitDBus() {
Andrew Moylanef116f92018-04-11 15:12:38 +100059 // Get or create the ExportedObject for the ML service.
60 dbus::ExportedObject* const ml_service_exported_object =
61 bus_->GetExportedObject(dbus::ObjectPath(kMlServicePath));
62 CHECK(ml_service_exported_object);
63
64 // Register a handler of the BootstrapMojoConnection method.
65 CHECK(ml_service_exported_object->ExportMethodAndBlock(
66 kMlInterfaceName, kBootstrapMojoConnectionMethod,
67 base::Bind(&Daemon::BootstrapMojoConnection,
68 weak_ptr_factory_.GetWeakPtr())));
69
70 // Take ownership of the ML service.
71 CHECK(bus_->RequestOwnershipAndBlock(kMlServiceName,
72 dbus::Bus::REQUIRE_PRIMARY));
Ken Turneredb93932018-02-14 05:27:31 +110073}
74
75void Daemon::BootstrapMojoConnection(
76 dbus::MethodCall* method_call,
77 dbus::ExportedObject::ResponseSender response_sender) {
Andrew Moylanff6be512018-07-03 11:05:01 +100078 if (machine_learning_service_) {
79 LOG(ERROR) << "MachineLearningService already instantiated";
80 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
81 method_call, DBUS_ERROR_FAILED, "Bootstrap already completed"));
82 return;
83 }
Andrew Moylanef116f92018-04-11 15:12:38 +100084
Andrew Moylanff6be512018-07-03 11:05:01 +100085 base::ScopedFD file_handle;
86 dbus::MessageReader reader(method_call);
Andrew Moylanef116f92018-04-11 15:12:38 +100087
Andrew Moylanff6be512018-07-03 11:05:01 +100088 if (!reader.PopFileDescriptor(&file_handle)) {
89 LOG(ERROR) << "Couldn't extract file descriptor from D-Bus call";
90 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
91 method_call, DBUS_ERROR_INVALID_ARGS, "Expected file descriptor"));
92 return;
93 }
94
95 if (!file_handle.is_valid()) {
96 LOG(ERROR) << "ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
97 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
98 method_call, DBUS_ERROR_INVALID_ARGS,
99 "Invalid (empty) file descriptor"));
100 return;
101 }
102
103 if (!base::SetCloseOnExec(file_handle.get())) {
104 PLOG(ERROR) << "Failed setting FD_CLOEXEC on file descriptor";
105 response_sender.Run(dbus::ErrorResponse::FromMethodCall(
106 method_call, DBUS_ERROR_FAILED,
107 "Failed setting FD_CLOEXEC on file descriptor"));
108 return;
109 }
110
111 // Connect to mojo in the requesting process.
112 mojo::edk::SetParentPipeHandle(mojo::edk::ScopedPlatformHandle(
113 mojo::edk::PlatformHandle(file_handle.release())));
114
115 // Bind primordial message pipe to a MachineLearningService implementation.
116 machine_learning_service_ = base::MakeUnique<MachineLearningServiceImpl>(
117 mojo::edk::CreateChildMessagePipe(kBootstrapMojoConnectionChannelToken),
118 base::Bind(&Daemon::OnConnectionError, base::Unretained(this)));
119
120 // Send success response.
121 response_sender.Run(dbus::Response::FromMethodCall(method_call));
122}
123
124void Daemon::OnConnectionError() {
125 // Die upon Mojo error. Reconnection can occur when the daemon is restarted.
126 // (A future Mojo API may enable Mojo re-bootstrap without a process restart.)
127 Quit();
Ken Turneredb93932018-02-14 05:27:31 +1100128}
129
130} // namespace ml