• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/commands/cvd/server.h"
18 
19 #include <signal.h>
20 #include <unistd.h>
21 
22 #include <atomic>
23 #include <future>
24 #include <map>
25 #include <mutex>
26 #include <optional>
27 #include <thread>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/strings.h>
32 #include <fruit/fruit.h>
33 
34 #include "cvd_server.pb.h"
35 
36 #include "common/libs/fs/shared_buf.h"
37 #include "common/libs/fs/shared_fd.h"
38 #include "common/libs/fs/shared_select.h"
39 #include "common/libs/utils/files.h"
40 #include "common/libs/utils/flag_parser.h"
41 #include "common/libs/utils/result.h"
42 #include "common/libs/utils/scope_guard.h"
43 #include "common/libs/utils/shared_fd_flag.h"
44 #include "common/libs/utils/subprocess.h"
45 #include "host/commands/cvd/build_api.h"
46 #include "host/commands/cvd/command_sequence.h"
47 #include "host/commands/cvd/demo_multi_vd.h"
48 #include "host/commands/cvd/epoll_loop.h"
49 #include "host/commands/cvd/logger.h"
50 #include "host/commands/cvd/server_command/acloud.h"
51 #include "host/commands/cvd/server_command/cmd_list.h"
52 #include "host/commands/cvd/server_command/crosvm.h"
53 #include "host/commands/cvd/server_command/display.h"
54 #include "host/commands/cvd/server_command/env.h"
55 #include "host/commands/cvd/server_command/generic.h"
56 #include "host/commands/cvd/server_command/handler_proxy.h"
57 #include "host/commands/cvd/server_command/load_configs.h"
58 #include "host/commands/cvd/server_command/operation_to_bins_map.h"
59 #include "host/commands/cvd/server_command/power.h"
60 #include "host/commands/cvd/server_command/reset.h"
61 #include "host/commands/cvd/server_command/start.h"
62 #include "host/commands/cvd/server_command/subcmd.h"
63 #include "host/commands/cvd/server_constants.h"
64 #include "host/libs/config/cuttlefish_config.h"
65 #include "host/libs/config/inject.h"
66 #include "host/libs/config/known_paths.h"
67 
68 namespace cuttlefish {
69 
70 static constexpr int kNumThreads = 10;
71 
CvdServer(BuildApi & build_api,EpollPool & epoll_pool,InstanceManager & instance_manager,HostToolTargetManager & host_tool_target_manager,ServerLogger & server_logger)72 CvdServer::CvdServer(BuildApi& build_api, EpollPool& epoll_pool,
73                      InstanceManager& instance_manager,
74                      HostToolTargetManager& host_tool_target_manager,
75                      ServerLogger& server_logger)
76     : build_api_(build_api),
77       epoll_pool_(epoll_pool),
78       instance_manager_(instance_manager),
79       host_tool_target_manager_(host_tool_target_manager),
80       server_logger_(server_logger),
81       running_(true),
82       optout_(false) {
83   std::scoped_lock lock(threads_mutex_);
84   for (auto i = 0; i < kNumThreads; i++) {
85     threads_.emplace_back([this]() {
86       while (running_) {
87         auto result = epoll_pool_.HandleEvent();
88         if (!result.ok()) {
89           LOG(ERROR) << "Epoll worker error:\n" << result.error().Message();
90           LOG(DEBUG) << "Epoll worker error:\n" << result.error().Trace();
91         }
92       }
93       auto wakeup = BestEffortWakeup();
94       CHECK(wakeup.ok()) << wakeup.error().Trace();
95     });
96   }
97 }
98 
~CvdServer()99 CvdServer::~CvdServer() {
100   running_ = false;
101   auto wakeup = BestEffortWakeup();
102   CHECK(wakeup.ok()) << wakeup.error().Trace();
103   Join();
104 }
105 
RequestComponent(CvdServer * server)106 fruit::Component<> CvdServer::RequestComponent(CvdServer* server) {
107   return fruit::createComponent()
108       .bindInstance(*server)
109       .bindInstance(server->instance_manager_)
110       .bindInstance(server->build_api_)
111       .bindInstance(server->host_tool_target_manager_)
112       .bindInstance<
113           fruit::Annotated<AcloudTranslatorOptOut, std::atomic<bool>>>(
114           server->optout_)
115       .install(CvdAcloudComponent)
116       .install(CvdCmdlistComponent)
117       .install(CommandSequenceExecutorComponent)
118       .install(CvdCrosVmComponent)
119       .install(cvdCommandComponent)
120       .install(CvdDevicePowerComponent)
121       .install(CvdDisplayComponent)
122       .install(CvdEnvComponent)
123       .install(cvdGenericCommandComponent)
124       .install(CvdHandlerProxyComponent)
125       .install(CvdHelpComponent)
126       .install(CvdResetComponent)
127       .install(CvdRestartComponent)
128       .install(cvdShutdownComponent)
129       .install(CvdStartCommandComponent)
130       .install(cvdVersionComponent)
131       .install(DemoMultiVdComponent)
132       .install(LoadConfigsComponent);
133 }
134 
BestEffortWakeup()135 Result<void> CvdServer::BestEffortWakeup() {
136   // This attempts to cascade through the responder threads, forcing them
137   // to wake up and see that running_ is false, then exit and wake up
138   // further threads.
139   auto eventfd = SharedFD::Event();
140   CF_EXPECT(eventfd->IsOpen(), eventfd->StrError());
141   CF_EXPECT(eventfd->EventfdWrite(1) == 0, eventfd->StrError());
142 
143   auto cb = [](EpollEvent) -> Result<void> { return {}; };
144   CF_EXPECT(epoll_pool_.Register(eventfd, EPOLLIN, cb));
145   return {};
146 }
147 
Stop()148 void CvdServer::Stop() {
149   {
150     std::lock_guard lock(ongoing_requests_mutex_);
151     running_ = false;
152   }
153   while (true) {
154     std::shared_ptr<OngoingRequest> request;
155     {
156       std::lock_guard lock(ongoing_requests_mutex_);
157       if (ongoing_requests_.empty()) {
158         break;
159       }
160       auto it = ongoing_requests_.begin();
161       request = *it;
162       ongoing_requests_.erase(it);
163     }
164     {
165       std::lock_guard lock(request->mutex);
166       if (request->handler == nullptr) {
167         continue;
168       }
169       request->handler->Interrupt();
170     }
171     auto wakeup = BestEffortWakeup();
172     CHECK(wakeup.ok()) << wakeup.error().Trace();
173     std::scoped_lock lock(threads_mutex_);
174     for (auto& thread : threads_) {
175       auto current_thread = thread.get_id() == std::this_thread::get_id();
176       auto matching_thread = thread.get_id() == request->thread_id;
177       if (!current_thread && matching_thread && thread.joinable()) {
178         thread.join();
179       }
180     }
181   }
182 }
183 
Join()184 void CvdServer::Join() {
185   for (auto& thread : threads_) {
186     if (thread.joinable()) {
187       thread.join();
188     }
189   }
190 }
191 
Exec(const ExecParam & exec_param)192 Result<void> CvdServer::Exec(const ExecParam& exec_param) {
193   CF_EXPECT(server_fd_->IsOpen(), "Server not running");
194   Stop();
195   android::base::unique_fd server_dup{server_fd_->UNMANAGED_Dup()};
196   CF_EXPECT(server_dup.get() >= 0, "dup: \"" << server_fd_->StrError() << "\"");
197   android::base::unique_fd client_dup{
198       exec_param.carryover_client_fd->UNMANAGED_Dup()};
199   CF_EXPECT(client_dup.get() >= 0, "dup: \"" << server_fd_->StrError() << "\"");
200   android::base::unique_fd client_stderr_dup{
201       exec_param.client_stderr_fd->UNMANAGED_Dup()};
202   CF_EXPECT(client_stderr_dup.get() >= 0,
203             "dup: \"" << exec_param.client_stderr_fd->StrError() << "\"");
204   cvd_common::Args argv_str = {
205       kServerExecPath,
206       "-INTERNAL_server_fd=" + std::to_string(server_dup.get()),
207       "-INTERNAL_carryover_client_fd=" + std::to_string(client_dup.get()),
208       "-INTERNAL_carryover_stderr_fd=" +
209           std::to_string(client_stderr_dup.get()),
210   };
211 
212   int in_memory_dup = -1;
213   ScopeGuard exit_action([&in_memory_dup]() {
214     if (in_memory_dup >= 0) {
215       if (close(in_memory_dup) != 0) {
216         LOG(ERROR) << "Failed to close file " << in_memory_dup;
217       }
218     }
219   });
220   if (exec_param.in_memory_data_fd) {
221     in_memory_dup = exec_param.in_memory_data_fd.value()->UNMANAGED_Dup();
222     CF_EXPECT(
223         in_memory_dup >= 0,
224         "dup: \"" << exec_param.in_memory_data_fd.value()->StrError() << "\"");
225     argv_str.push_back("-INTERNAL_memory_carryover_fd=" +
226                        std::to_string(in_memory_dup));
227   }
228 
229   std::vector<char*> argv_cstr;
230   for (const auto& argv : argv_str) {
231     argv_cstr.emplace_back(strdup(argv.c_str()));
232   }
233   argv_cstr.emplace_back(nullptr);
234   android::base::unique_fd new_exe_dup{exec_param.new_exe->UNMANAGED_Dup()};
235   CF_EXPECT(new_exe_dup.get() >= 0,
236             "dup: \"" << exec_param.new_exe->StrError() << "\"");
237 
238   if (exec_param.verbose) {
239     LOG(ERROR) << "Server Exec'ing: " << android::base::Join(argv_str, " ");
240   }
241 
242   fexecve(new_exe_dup.get(), argv_cstr.data(), environ);
243   for (const auto& argv : argv_cstr) {
244     free(argv);
245   }
246   return CF_ERR("fexecve failed: \"" << strerror(errno) << "\"");
247 }
248 
RequestHandler(const RequestWithStdio & request,const std::vector<CvdServerHandler * > & handlers)249 Result<CvdServerHandler*> RequestHandler(
250     const RequestWithStdio& request,
251     const std::vector<CvdServerHandler*>& handlers) {
252   Result<cvd::Response> response;
253   std::vector<CvdServerHandler*> compatible_handlers;
254   for (auto& handler : handlers) {
255     if (CF_EXPECT(handler->CanHandle(request))) {
256       compatible_handlers.push_back(handler);
257     }
258   }
259   CF_EXPECT(compatible_handlers.size() == 1,
260             "Expected exactly one handler for message, found "
261                 << compatible_handlers.size());
262   return compatible_handlers[0];
263 }
264 
StartServer(SharedFD server_fd)265 Result<void> CvdServer::StartServer(SharedFD server_fd) {
266   server_fd_ = server_fd;
267   auto cb = [this](EpollEvent ev) -> Result<void> {
268     CF_EXPECT(AcceptClient(ev));
269     return {};
270   };
271   CF_EXPECT(epoll_pool_.Register(server_fd, EPOLLIN, cb));
272   return {};
273 }
274 
AcceptCarryoverClient(SharedFD client,std::unique_ptr<ServerLogger::ScopedLogger>)275 Result<void> CvdServer::AcceptCarryoverClient(
276     SharedFD client,
277     // the passed ScopedLogger should be destroyed on return of this function.
278     std::unique_ptr<ServerLogger::ScopedLogger>) {
279   auto self_cb = [this](EpollEvent ev) -> Result<void> {
280     CF_EXPECT(HandleMessage(ev));
281     return {};
282   };
283   CF_EXPECT(epoll_pool_.Register(client, EPOLLIN, self_cb));
284 
285   cvd::Response success_message;
286   success_message.mutable_status()->set_code(cvd::Status::OK);
287   success_message.mutable_command_response();
288   CF_EXPECT(SendResponse(client, success_message));
289   return {};
290 }
291 
AcceptClient(EpollEvent event)292 Result<void> CvdServer::AcceptClient(EpollEvent event) {
293   ScopeGuard stop_on_failure([this] { Stop(); });
294 
295   CF_EXPECT(event.events & EPOLLIN);
296   auto client_fd = SharedFD::Accept(*event.fd);
297   CF_EXPECT(client_fd->IsOpen(), client_fd->StrError());
298   auto client_cb = [this](EpollEvent ev) -> Result<void> {
299     CF_EXPECT(HandleMessage(ev));
300     return {};
301   };
302   CF_EXPECT(epoll_pool_.Register(client_fd, EPOLLIN, client_cb));
303 
304   auto self_cb = [this](EpollEvent ev) -> Result<void> {
305     CF_EXPECT(AcceptClient(ev));
306     return {};
307   };
308   CF_EXPECT(epoll_pool_.Register(event.fd, EPOLLIN, self_cb));
309 
310   stop_on_failure.Cancel();
311   return {};
312 }
313 
HandleMessage(EpollEvent event)314 Result<void> CvdServer::HandleMessage(EpollEvent event) {
315   ScopeGuard abandon_client([this, event] { epoll_pool_.Remove(event.fd); });
316 
317   if (event.events & EPOLLHUP) {  // Client went away.
318     epoll_pool_.Remove(event.fd);
319     return {};
320   }
321 
322   CF_EXPECT(event.events & EPOLLIN);
323   auto request = CF_EXPECT(GetRequest(event.fd));
324   if (!request) {  // End-of-file / client went away.
325     epoll_pool_.Remove(event.fd);
326     return {};
327   }
328 
329   auto logger = server_logger_.LogThreadToFd(request->Err());
330   auto response = HandleRequest(*request, event.fd);
331   if (!response.ok()) {
332     cvd::Response failure_message;
333     failure_message.mutable_status()->set_code(cvd::Status::INTERNAL);
334     failure_message.mutable_status()->set_message(response.error().Trace());
335     CF_EXPECT(SendResponse(event.fd, failure_message));
336     return {};  // Error already sent to the client, don't repeat on the server
337   }
338   CF_EXPECT(SendResponse(event.fd, *response));
339 
340   auto self_cb = [this, err = request->Err()](EpollEvent ev) -> Result<void> {
341     CF_EXPECT(HandleMessage(ev));
342     return {};
343   };
344   CF_EXPECT(epoll_pool_.Register(event.fd, EPOLLIN, self_cb));
345 
346   abandon_client.Cancel();
347   return {};
348 }
349 
350 // convert HOME, ANDROID_HOST_OUT, ANDROID_SOONG_HOST_OUT
351 // and ANDROID_PRODUCT_OUT into absolute paths if any.
ConvertDirPathToAbsolute(const RequestWithStdio & request)352 static Result<RequestWithStdio> ConvertDirPathToAbsolute(
353     const RequestWithStdio& request) {
354   if (request.Message().contents_case() !=
355       cvd::Request::ContentsCase::kCommandRequest) {
356     return request;
357   }
358   if (request.Message().command_request().env().empty()) {
359     return request;
360   }
361   auto envs =
362       cvd_common::ConvertToEnvs(request.Message().command_request().env());
363   std::unordered_set<std::string> interested_envs{
364       kAndroidHostOut, kAndroidSoongHostOut, "HOME", kAndroidProductOut};
365   const auto& current_dir =
366       request.Message().command_request().working_directory();
367 
368   // make sure that "~" is not included
369   for (const auto& key : interested_envs) {
370     if (!Contains(envs, key)) {
371       continue;
372     }
373     const auto& dir = envs.at(key);
374     CF_EXPECT(dir != "~" && !android::base::StartsWith(dir, "~/"),
375               "The " << key << " directory should not start with ~");
376   }
377 
378   for (const auto& key : interested_envs) {
379     if (!Contains(envs, key)) {
380       continue;
381     }
382     const auto dir = envs.at(key);
383     envs[key] =
384         CF_EXPECT(EmulateAbsolutePath({.current_working_dir = current_dir,
385                                        .home_dir = std::nullopt,  // unused
386                                        .path_to_convert = dir,
387                                        .follow_symlink = false}));
388   }
389 
390   auto cmd_args =
391       cvd_common::ConvertToArgs(request.Message().command_request().args());
392   auto selector_args = cvd_common::ConvertToArgs(
393       request.Message().command_request().selector_opts().args());
394   RequestWithStdio new_request(
395       request.Client(),
396       MakeRequest({.cmd_args = std::move(cmd_args),
397                    .selector_args = std::move(selector_args),
398                    .env = std::move(envs),
399                    .working_dir = current_dir},
400                   request.Message().command_request().wait_behavior()),
401       request.FileDescriptors(), request.Credentials());
402   return new_request;
403 }
404 
VerifyUser(const RequestWithStdio & request)405 static Result<void> VerifyUser(const RequestWithStdio& request) {
406   CF_EXPECT(request.Credentials(),
407             "ucred is not available while it is necessary.");
408   const uid_t client_uid = request.Credentials()->uid;
409   CF_EXPECT_EQ(client_uid, getuid(), "Cvd server process is one per user.");
410   return {};
411 }
412 
HandleRequest(RequestWithStdio orig_request,SharedFD client)413 Result<cvd::Response> CvdServer::HandleRequest(RequestWithStdio orig_request,
414                                                SharedFD client) {
415   CF_EXPECT(VerifyUser(orig_request));
416   auto request = CF_EXPECT(ConvertDirPathToAbsolute(orig_request));
417   fruit::Injector<> injector(RequestComponent, this);
418 
419   for (auto& late_injected : injector.getMultibindings<LateInjected>()) {
420     CF_EXPECT(late_injected->LateInject(injector));
421   }
422 
423   auto possible_handlers = injector.getMultibindings<CvdServerHandler>();
424 
425   // Even if the interrupt callback outlives the request handler, it'll only
426   // hold on to this struct which will be cleaned out when the request handler
427   // exits.
428   auto shared = std::make_shared<OngoingRequest>();
429   shared->handler = CF_EXPECT(RequestHandler(request, possible_handlers));
430   shared->thread_id = std::this_thread::get_id();
431 
432   {
433     std::lock_guard lock(ongoing_requests_mutex_);
434     if (running_) {
435       ongoing_requests_.insert(shared);
436     } else {
437       // We're executing concurrently with a Stop() call.
438       return {};
439     }
440   }
441   ScopeGuard remove_ongoing_request([this, shared] {
442     std::lock_guard lock(ongoing_requests_mutex_);
443     ongoing_requests_.erase(shared);
444   });
445 
446   auto interrupt_cb = [this, shared,
447                        err = request.Err()](EpollEvent) -> Result<void> {
448     auto logger = server_logger_.LogThreadToFd(err);
449     std::lock_guard lock(shared->mutex);
450     CF_EXPECT(shared->handler != nullptr);
451     CF_EXPECT(shared->handler->Interrupt());
452     return {};
453   };
454   CF_EXPECT(epoll_pool_.Register(client, EPOLLHUP, interrupt_cb));
455 
456   auto response = CF_EXPECT(shared->handler->Handle(request));
457   {
458     std::lock_guard lock(shared->mutex);
459     shared->handler = nullptr;
460   }
461   CF_EXPECT(epoll_pool_.Remove(client));  // Delete interrupt handler
462 
463   return response;
464 }
465 
InstanceDbFromJson(const std::string & json_string)466 Result<void> CvdServer::InstanceDbFromJson(const std::string& json_string) {
467   const uid_t uid = getuid();
468   auto json = CF_EXPECT(ParseJson(json_string));
469   CF_EXPECT(instance_manager_.LoadFromJson(uid, json));
470   return {};
471 }
472 
ServerComponent(ServerLogger * server_logger)473 static fruit::Component<> ServerComponent(ServerLogger* server_logger) {
474   return fruit::createComponent()
475       .addMultibinding<CvdServer, CvdServer>()
476       .bindInstance(*server_logger)
477       .install(BuildApiModule)
478       .install(EpollLoopComponent)
479       .install(HostToolTargetManagerComponent)
480       .install(OperationToBinsMapComponent);
481 }
482 
CvdServerMain(ServerMainParam && fds)483 Result<int> CvdServerMain(ServerMainParam&& fds) {
484   LOG(INFO) << "Starting server";
485 
486   CF_EXPECT(daemon(0, 0) != -1, strerror(errno));
487 
488   signal(SIGPIPE, SIG_IGN);
489 
490   SharedFD server_fd = std::move(fds.internal_server_fd);
491   CF_EXPECT(server_fd->IsOpen(), "Did not receive a valid cvd_server fd");
492 
493   std::unique_ptr<ServerLogger> server_logger = std::move(fds.server_logger);
494   fruit::Injector<> injector(ServerComponent, server_logger.get());
495 
496   for (auto& late_injected : injector.getMultibindings<LateInjected>()) {
497     CF_EXPECT(late_injected->LateInject(injector));
498   }
499 
500   auto server_bindings = injector.getMultibindings<CvdServer>();
501   CF_EXPECT(server_bindings.size() == 1,
502             "Expected 1 server binding, got " << server_bindings.size());
503   auto& server = *(server_bindings[0]);
504 
505   std::optional<SharedFD> memory_carryover_fd =
506       std::move(fds.memory_carryover_fd);
507   if (memory_carryover_fd) {
508     const std::string json_string =
509         CF_EXPECT(ReadAllFromMemFd(*memory_carryover_fd));
510     CF_EXPECT(server.InstanceDbFromJson(json_string),
511               "Failed to load from: " << json_string);
512   }
513 
514   server.StartServer(server_fd);
515 
516   SharedFD carryover_client = std::move(fds.carryover_client_fd);
517   // The carryover_client wouldn't be available after AcceptCarryoverClient()
518   if (carryover_client->IsOpen()) {
519     // release scoped_logger for this thread inside AcceptCarryoverClient()
520     CF_EXPECT(server.AcceptCarryoverClient(carryover_client,
521                                            std::move(fds.scoped_logger)));
522   } else {
523     // release scoped_logger now and delete the object
524     fds.scoped_logger.reset();
525   }
526   server.Join();
527 
528   return 0;
529 }
530 
ReadAllFromMemFd(const SharedFD & mem_fd)531 Result<std::string> ReadAllFromMemFd(const SharedFD& mem_fd) {
532   const auto n_message_size = mem_fd->LSeek(0, SEEK_END);
533   CF_EXPECT_NE(n_message_size, -1, "LSeek on the memory file failed.");
534   std::vector<char> buffer(n_message_size);
535   CF_EXPECT_EQ(mem_fd->LSeek(0, SEEK_SET), 0, mem_fd->StrError());
536   auto n_read = ReadExact(mem_fd, buffer.data(), n_message_size);
537   CF_EXPECT(n_read == n_message_size,
538             "Expected to read " << n_message_size << " bytes but actually read "
539                                 << n_read << " bytes.");
540   std::string message(buffer.begin(), buffer.end());
541   return message;
542 }
543 
544 }  // namespace cuttlefish
545