blob: 3214c0de2090c4dad7677dc554dc9da724534078 [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 <memory>
8#include <utility>
9
Honglin Yu7b6c1192020-09-16 10:07:17 +100010#include <sys/types.h>
11#include <sysexits.h>
12#include <unistd.h>
13
Andrew Moylanef116f92018-04-11 15:12:38 +100014#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090015#include <base/check.h>
Andrew Moylanff6be512018-07-03 11:05:01 +100016#include <base/files/file_util.h>
Andrew Moylanef116f92018-04-11 15:12:38 +100017#include <base/memory/ref_counted.h>
18#include <chromeos/dbus/service_constants.h>
19#include <dbus/bus.h>
20#include <dbus/message.h>
Qijiang Fan7da812d2019-11-26 10:48:46 +090021#include <mojo/core/embedder/embedder.h>
Qijiang Fan3b917c72019-12-09 15:24:15 +090022#include <mojo/public/cpp/system/invitation.h>
Andrew Moylanff6be512018-07-03 11:05:01 +100023
Charles Zhaod4fb7b62020-08-25 17:21:58 +100024#include "ml/dlcservice_client.h"
Andrew Moylanff6be512018-07-03 11:05:01 +100025#include "ml/machine_learning_service_impl.h"
Honglin Yu21616692021-05-14 11:20:22 +100026#include "ml/request_metrics.h"
Andrew Moylanef116f92018-04-11 15:12:38 +100027
Ken Turneredb93932018-02-14 05:27:31 +110028namespace ml {
29
Andrew Moylanef116f92018-04-11 15:12:38 +100030Daemon::Daemon() : weak_ptr_factory_(this) {}
Ken Turneredb93932018-02-14 05:27:31 +110031
32Daemon::~Daemon() {}
33
34int Daemon::OnInit() {
Andrew Moylanef116f92018-04-11 15:12:38 +100035 int exit_code = DBusDaemon::OnInit();
Honglin Yu7b6c1192020-09-16 10:07:17 +100036 if (exit_code != EX_OK) {
37 LOG(ERROR) << "DBusDaemon::OnInit() failed";
Andrew Moylanef116f92018-04-11 15:12:38 +100038 return exit_code;
Honglin Yu7b6c1192020-09-16 10:07:17 +100039 }
40 // For control process, we need to change euid back to 0. We need the control
41 // process to be root in the user namespace because it needs to spawn worker
42 // processes and sandbox them.
43 if (seteuid(0) != 0) {
Honglin Yu21616692021-05-14 11:20:22 +100044 RecordProcessErrorEvent(ProcessError::kChangeEuidBackToRootFailed);
Honglin Yu7b6c1192020-09-16 10:07:17 +100045 LOG(ERROR) << "Unable to change effective uid back to 0";
46 exit(EX_OSERR);
47 }
Andrew Moylanef116f92018-04-11 15:12:38 +100048
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100049 metrics_.StartCollectingProcessMetrics();
Qijiang Fan7da812d2019-11-26 10:48:46 +090050 mojo::core::Init();
51 ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
52 base::ThreadTaskRunnerHandle::Get(),
53 mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
Ken Turneredb93932018-02-14 05:27:31 +110054 InitDBus();
Andrew Moylanff6be512018-07-03 11:05:01 +100055
Ken Turneredb93932018-02-14 05:27:31 +110056 return 0;
57}
58
59void Daemon::InitDBus() {
Andrew Moylanef116f92018-04-11 15:12:38 +100060 // Get or create the ExportedObject for the ML service.
61 dbus::ExportedObject* const ml_service_exported_object =
Andrew Moylan49f50b32018-07-27 08:48:11 +100062 bus_->GetExportedObject(dbus::ObjectPath(kMachineLearningServicePath));
Andrew Moylanef116f92018-04-11 15:12:38 +100063 CHECK(ml_service_exported_object);
64
65 // Register a handler of the BootstrapMojoConnection method.
66 CHECK(ml_service_exported_object->ExportMethodAndBlock(
Andrew Moylan49f50b32018-07-27 08:48:11 +100067 kMachineLearningInterfaceName, kBootstrapMojoConnectionMethod,
Andrew Moylanef116f92018-04-11 15:12:38 +100068 base::Bind(&Daemon::BootstrapMojoConnection,
69 weak_ptr_factory_.GetWeakPtr())));
70
71 // Take ownership of the ML service.
Andrew Moylan49f50b32018-07-27 08:48:11 +100072 CHECK(bus_->RequestOwnershipAndBlock(kMachineLearningServiceName,
Andrew Moylanef116f92018-04-11 15:12:38 +100073 dbus::Bus::REQUIRE_PRIMARY));
Ken Turneredb93932018-02-14 05:27:31 +110074}
75
76void Daemon::BootstrapMojoConnection(
77 dbus::MethodCall* method_call,
78 dbus::ExportedObject::ResponseSender response_sender) {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +100079 metrics_.RecordMojoConnectionEvent(
80 Metrics::MojoConnectionEvent::kBootstrapRequested);
Andrew Moylanff6be512018-07-03 11:05:01 +100081 if (machine_learning_service_) {
82 LOG(ERROR) << "MachineLearningService already instantiated";
Qijiang Fan795b81f2020-07-06 12:36:18 +090083 std::move(response_sender)
84 .Run(dbus::ErrorResponse::FromMethodCall(
85 method_call, DBUS_ERROR_FAILED, "Bootstrap already completed"));
Andrew Moylanff6be512018-07-03 11:05:01 +100086 return;
87 }
Andrew Moylanef116f92018-04-11 15:12:38 +100088
Andrew Moylanff6be512018-07-03 11:05:01 +100089 base::ScopedFD file_handle;
90 dbus::MessageReader reader(method_call);
Andrew Moylanef116f92018-04-11 15:12:38 +100091
Andrew Moylanff6be512018-07-03 11:05:01 +100092 if (!reader.PopFileDescriptor(&file_handle)) {
93 LOG(ERROR) << "Couldn't extract file descriptor from D-Bus call";
Qijiang Fan795b81f2020-07-06 12:36:18 +090094 std::move(response_sender)
95 .Run(dbus::ErrorResponse::FromMethodCall(
96 method_call, DBUS_ERROR_INVALID_ARGS, "Expected file descriptor"));
Andrew Moylanff6be512018-07-03 11:05:01 +100097 return;
98 }
99
100 if (!file_handle.is_valid()) {
101 LOG(ERROR) << "ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
Qijiang Fan795b81f2020-07-06 12:36:18 +0900102 std::move(response_sender)
103 .Run(dbus::ErrorResponse::FromMethodCall(
104 method_call, DBUS_ERROR_INVALID_ARGS,
105 "Invalid (empty) file descriptor"));
Andrew Moylanff6be512018-07-03 11:05:01 +1000106 return;
107 }
108
109 if (!base::SetCloseOnExec(file_handle.get())) {
110 PLOG(ERROR) << "Failed setting FD_CLOEXEC on file descriptor";
Qijiang Fan795b81f2020-07-06 12:36:18 +0900111 std::move(response_sender)
112 .Run(dbus::ErrorResponse::FromMethodCall(
113 method_call, DBUS_ERROR_FAILED,
114 "Failed setting FD_CLOEXEC on file descriptor"));
Andrew Moylanff6be512018-07-03 11:05:01 +1000115 return;
116 }
117
118 // Connect to mojo in the requesting process.
Qijiang Fan3b917c72019-12-09 15:24:15 +0900119 mojo::IncomingInvitation invitation =
120 mojo::IncomingInvitation::Accept(mojo::PlatformChannelEndpoint(
121 mojo::PlatformHandle(std::move(file_handle))));
Andrew Moylanff6be512018-07-03 11:05:01 +1000122
123 // Bind primordial message pipe to a MachineLearningService implementation.
hscham3f45fcc2019-12-25 16:54:54 +0900124 machine_learning_service_ = std::make_unique<MachineLearningServiceImpl>(
hschamd13deea2021-03-08 09:46:15 +0900125 mojo::PendingReceiver<
126 chromeos::machine_learning::mojom::MachineLearningService>(
127 invitation.ExtractMessagePipe(kBootstrapMojoConnectionChannelToken)),
Charles Zhaod4fb7b62020-08-25 17:21:58 +1000128 base::Bind(&Daemon::OnMojoDisconnection, base::Unretained(this)),
129 bus_.get());
Andrew Moylanff6be512018-07-03 11:05:01 +1000130
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000131 metrics_.RecordMojoConnectionEvent(
132 Metrics::MojoConnectionEvent::kBootstrapSucceeded);
133
Andrew Moylanff6be512018-07-03 11:05:01 +1000134 // Send success response.
Qijiang Fan795b81f2020-07-06 12:36:18 +0900135 std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
Andrew Moylanff6be512018-07-03 11:05:01 +1000136}
137
Andrew Moylanb481af72020-07-09 15:22:00 +1000138void Daemon::OnMojoDisconnection() {
Andrew Moylan40ee4fc2018-08-24 15:46:09 +1000139 metrics_.RecordMojoConnectionEvent(
Andrew Moylanb481af72020-07-09 15:22:00 +1000140 Metrics::MojoConnectionEvent::kConnectionClosed);
141 // Die upon disconnection . Reconnection can occur when the daemon is
142 // restarted. (A future Mojo API may enable Mojo re-bootstrap without a
143 // process restart.)
Andrew Moylanff6be512018-07-03 11:05:01 +1000144 Quit();
Ken Turneredb93932018-02-14 05:27:31 +1100145}
146
147} // namespace ml