blob: bc83768f89ab2bf65e5e7ed860afc0fc9afc964b [file] [log] [blame]
Tyler Chatowa79419d2020-08-12 20:12:11 -07001#include "starterd_lib.h"
2
3#include <fcntl.h>
4#include <pwd.h>
5#include <sys/fsuid.h>
6#include <sys/prctl.h>
7
8#include <algorithm>
9#include <utility>
10
James Kuszmaul293b2172021-11-10 16:20:48 -080011#include "absl/strings/str_format.h"
12#include "aos/json_to_flatbuffer.h"
Tyler Chatowa79419d2020-08-12 20:12:11 -070013#include "glog/logging.h"
14#include "glog/stl_logging.h"
15
16namespace aos {
17namespace starter {
18
19Application::Application(const aos::Application *application,
Austin Schuhfc304942021-10-16 14:20:05 -070020 aos::ShmEventLoop *event_loop,
21 std::function<void()> on_change)
Tyler Chatowa79419d2020-08-12 20:12:11 -070022 : name_(application->name()->string_view()),
23 path_(application->has_executable_name()
24 ? application->executable_name()->string_view()
25 : application->name()->string_view()),
Tyler Chatow2acff482020-12-19 22:29:04 -080026 args_(1),
Tyler Chatowa79419d2020-08-12 20:12:11 -070027 user_(application->has_user() ? FindUid(application->user()->c_str())
28 : std::nullopt),
Austin Schuh529ac592021-10-14 16:11:13 -070029 group_(application->has_user()
30 ? FindPrimaryGidForUser(application->user()->c_str())
31 : std::nullopt),
Austin Schuh5f79a5a2021-10-12 17:46:50 -070032 autostart_(application->autostart()),
Tyler Chatowa79419d2020-08-12 20:12:11 -070033 event_loop_(event_loop),
34 start_timer_(event_loop_->AddTimer([this] {
35 status_ = aos::starter::State::RUNNING;
Austin Schuh3204b332021-10-16 14:20:10 -070036 LOG(INFO) << "Started '" << name_ << "' pid: " << pid_;
Tyler Chatowa79419d2020-08-12 20:12:11 -070037 })),
38 restart_timer_(event_loop_->AddTimer([this] { DoStart(); })),
39 stop_timer_(event_loop_->AddTimer([this] {
40 if (kill(pid_, SIGKILL) == 0) {
Austin Schuh3204b332021-10-16 14:20:10 -070041 LOG(WARNING) << "Failed to stop, sending SIGKILL to '" << name_
42 << "' pid: " << pid_;
Tyler Chatowa79419d2020-08-12 20:12:11 -070043 }
Austin Schuhfc304942021-10-16 14:20:05 -070044 })),
45 on_change_(on_change) {}
Tyler Chatowa79419d2020-08-12 20:12:11 -070046
47void Application::DoStart() {
48 if (status_ != aos::starter::State::WAITING) {
49 return;
50 }
51
52 start_timer_->Disable();
53 restart_timer_->Disable();
54
Tyler Chatowa79419d2020-08-12 20:12:11 -070055 std::tie(read_pipe_, write_pipe_) = ScopedPipe::MakePipe();
56
57 const pid_t pid = fork();
58
59 if (pid != 0) {
60 if (pid == -1) {
Austin Schuh3204b332021-10-16 14:20:10 -070061 PLOG(WARNING) << "Failed to fork '" << name_ << "'";
Tyler Chatowa79419d2020-08-12 20:12:11 -070062 stop_reason_ = aos::starter::LastStopReason::FORK_ERR;
63 status_ = aos::starter::State::STOPPED;
64 } else {
65 pid_ = pid;
66 id_ = next_id_++;
67 start_time_ = event_loop_->monotonic_now();
68 status_ = aos::starter::State::STARTING;
Austin Schuh3204b332021-10-16 14:20:10 -070069 LOG(INFO) << "Starting '" << name_ << "' pid " << pid_;
Tyler Chatowa79419d2020-08-12 20:12:11 -070070
71 // Setup timer which moves application to RUNNING state if it is still
72 // alive in 1 second.
73 start_timer_->Setup(event_loop_->monotonic_now() +
74 std::chrono::seconds(1));
75 }
Austin Schuhfc304942021-10-16 14:20:05 -070076 on_change_();
Tyler Chatowa79419d2020-08-12 20:12:11 -070077 return;
78 }
79
80 // Clear out signal mask of parent so forked process receives all signals
81 // normally.
82 sigset_t empty_mask;
83 sigemptyset(&empty_mask);
84 sigprocmask(SIG_SETMASK, &empty_mask, nullptr);
85
86 // Cleanup children if starter dies in a way that is not handled gracefully.
87 if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) {
88 write_pipe_.Write(
89 static_cast<uint32_t>(aos::starter::LastStopReason::SET_PRCTL_ERR));
90 PLOG(FATAL) << "Could not set PR_SET_PDEATHSIG to SIGKILL";
91 }
92
Austin Schuh529ac592021-10-14 16:11:13 -070093 if (group_) {
94 if (setgid(*group_) == -1) {
95 write_pipe_.Write(
96 static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
97 PLOG(FATAL) << "Could not set group for " << name_ << " to " << *group_;
98 }
99 }
100
Tyler Chatowa79419d2020-08-12 20:12:11 -0700101 if (user_) {
Tyler Chatow03fdb2a2020-12-26 18:39:36 -0800102 if (setuid(*user_) == -1) {
Tyler Chatowa79419d2020-08-12 20:12:11 -0700103 write_pipe_.Write(
104 static_cast<uint32_t>(aos::starter::LastStopReason::SET_USR_ERR));
105 PLOG(FATAL) << "Could not set user for " << name_ << " to " << *user_;
106 }
107 }
108
109 // argv[0] should be the program name
110 args_.insert(args_.begin(), path_.data());
111
Austin Schuh529ac592021-10-14 16:11:13 -0700112 execvp(path_.c_str(), args_.data());
Tyler Chatowa79419d2020-08-12 20:12:11 -0700113
114 // If we got here, something went wrong
115 write_pipe_.Write(
116 static_cast<uint32_t>(aos::starter::LastStopReason::EXECV_ERR));
117 PLOG(WARNING) << "Could not execute " << name_ << " (" << path_ << ')';
118
119 _exit(EXIT_FAILURE);
120}
121
122void Application::DoStop(bool restart) {
123 // If stop or restart received, the old state of these is no longer applicable
124 // so cancel both.
125 restart_timer_->Disable();
126 start_timer_->Disable();
127
128 switch (status_) {
129 case aos::starter::State::STARTING:
130 case aos::starter::State::RUNNING: {
Austin Schuh3204b332021-10-16 14:20:10 -0700131 LOG(INFO) << "Stopping '" << name_ << "' pid: " << pid_ << " with signal "
132 << SIGINT;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700133 status_ = aos::starter::State::STOPPING;
134
135 kill(pid_, SIGINT);
136
137 // Watchdog timer to SIGKILL application if it is still running 1 second
138 // after SIGINT
139 stop_timer_->Setup(event_loop_->monotonic_now() +
140 std::chrono::seconds(1));
141 queue_restart_ = restart;
Austin Schuhfc304942021-10-16 14:20:05 -0700142 on_change_();
Tyler Chatowa79419d2020-08-12 20:12:11 -0700143 break;
144 }
145 case aos::starter::State::WAITING: {
146 // If waiting to restart, and receives restart, skip the waiting period
147 // and restart immediately. If stop received, all we have to do is move
148 // to the STOPPED state.
149 if (restart) {
150 DoStart();
151 } else {
152 status_ = aos::starter::State::STOPPED;
Austin Schuhfc304942021-10-16 14:20:05 -0700153 on_change_();
Tyler Chatowa79419d2020-08-12 20:12:11 -0700154 }
155 break;
156 }
157 case aos::starter::State::STOPPING: {
158 // If the application is already stopping, then we just need to update the
159 // restart flag to the most recent status.
160 queue_restart_ = restart;
161 break;
162 }
163 case aos::starter::State::STOPPED: {
164 // Restart immediately if the application is already stopped
165 if (restart) {
166 status_ = aos::starter::State::WAITING;
167 DoStart();
168 }
169 break;
170 }
171 }
172}
173
174void Application::QueueStart() {
175 status_ = aos::starter::State::WAITING;
176
Austin Schuha07b3ce2021-10-10 12:33:21 -0700177 LOG(INFO) << "Restarting " << name_ << " in 3 seconds";
178 restart_timer_->Setup(event_loop_->monotonic_now() + std::chrono::seconds(3));
Tyler Chatowa79419d2020-08-12 20:12:11 -0700179 start_timer_->Disable();
180 stop_timer_->Disable();
Austin Schuhfc304942021-10-16 14:20:05 -0700181 on_change_();
Tyler Chatowa79419d2020-08-12 20:12:11 -0700182}
183
184void Application::set_args(
185 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> &v) {
186 args_.clear();
187 std::transform(v.begin(), v.end(), std::back_inserter(args_),
188 [](const flatbuffers::String *str) {
189 return const_cast<char *>(str->c_str());
190 });
191 args_.push_back(nullptr);
192}
193
194std::optional<uid_t> Application::FindUid(const char *name) {
Austin Schuh529ac592021-10-14 16:11:13 -0700195 // TODO(austin): Use the reentrant version. This should be safe.
Tyler Chatowa79419d2020-08-12 20:12:11 -0700196 struct passwd *user_data = getpwnam(name);
197 if (user_data != nullptr) {
198 return user_data->pw_uid;
199 } else {
200 LOG(FATAL) << "Could not find user " << name;
201 return std::nullopt;
202 }
203}
204
Austin Schuh529ac592021-10-14 16:11:13 -0700205std::optional<gid_t> Application::FindPrimaryGidForUser(const char *name) {
206 // TODO(austin): Use the reentrant version. This should be safe.
207 struct passwd *user_data = getpwnam(name);
208 if (user_data != nullptr) {
209 return user_data->pw_gid;
210 } else {
211 LOG(FATAL) << "Could not find user " << name;
212 return std::nullopt;
213 }
214}
215
Tyler Chatowa79419d2020-08-12 20:12:11 -0700216flatbuffers::Offset<aos::starter::ApplicationStatus>
217Application::PopulateStatus(flatbuffers::FlatBufferBuilder *builder) {
218 CHECK_NOTNULL(builder);
219 auto name_fbs = builder->CreateString(name_);
220
221 aos::starter::ApplicationStatus::Builder status_builder(*builder);
222 status_builder.add_name(name_fbs);
223 status_builder.add_state(status_);
224 status_builder.add_last_exit_code(exit_code_);
225 status_builder.add_last_stop_reason(stop_reason_);
226 if (pid_ != -1) {
227 status_builder.add_pid(pid_);
228 status_builder.add_id(id_);
229 }
230 status_builder.add_last_start_time(start_time_.time_since_epoch().count());
231 return status_builder.Finish();
232}
233
234void Application::Terminate() {
235 stop_reason_ = aos::starter::LastStopReason::TERMINATE;
236 DoStop(false);
237 terminating_ = true;
238}
239
240void Application::HandleCommand(aos::starter::Command cmd) {
241 switch (cmd) {
242 case aos::starter::Command::START: {
243 switch (status_) {
244 case aos::starter::State::WAITING: {
245 restart_timer_->Disable();
246 DoStart();
247 break;
248 }
249 case aos::starter::State::STARTING: {
250 break;
251 }
252 case aos::starter::State::RUNNING: {
253 break;
254 }
255 case aos::starter::State::STOPPING: {
256 queue_restart_ = true;
257 break;
258 }
259 case aos::starter::State::STOPPED: {
260 status_ = aos::starter::State::WAITING;
261 DoStart();
262 break;
263 }
264 }
265 break;
266 }
267 case aos::starter::Command::STOP: {
268 stop_reason_ = aos::starter::LastStopReason::STOP_REQUESTED;
269 DoStop(false);
270 break;
271 }
272 case aos::starter::Command::RESTART: {
273 stop_reason_ = aos::starter::LastStopReason::RESTART_REQUESTED;
274 DoStop(true);
275 break;
276 }
277 }
278}
279
280bool Application::MaybeHandleSignal() {
281 int status;
282
283 // Check if the status of this process has changed
284 if (pid_ == -1 || waitpid(pid_, &status, WNOHANG) != pid_) {
285 return false;
286 }
287
288 // Check that the event was the process exiting
289 if (!WIFEXITED(status) && !WIFSIGNALED(status)) {
290 return false;
291 }
292
293 exit_time_ = event_loop_->monotonic_now();
294 exit_code_ = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status);
295
296 if (auto read_result = read_pipe_.Read()) {
297 stop_reason_ = static_cast<aos::starter::LastStopReason>(*read_result);
298 }
299
300 switch (status_) {
301 case aos::starter::State::STARTING: {
Austin Schuh3204b332021-10-16 14:20:10 -0700302 LOG(WARNING) << "Failed to start '" << name_ << "' on pid " << pid_
Tyler Chatowa79419d2020-08-12 20:12:11 -0700303 << " : Exited with status " << exit_code_;
304 QueueStart();
305 break;
306 }
307 case aos::starter::State::RUNNING: {
Austin Schuh3204b332021-10-16 14:20:10 -0700308 LOG(WARNING) << "Application '" << name_ << "' pid " << pid_
309 << " exited unexpectedly with status " << exit_code_;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700310 QueueStart();
311 break;
312 }
313 case aos::starter::State::STOPPING: {
Austin Schuh3204b332021-10-16 14:20:10 -0700314 LOG(INFO) << "Successfully stopped '" << name_ << "' pid: " << pid_
315 << " with status " << exit_code_;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700316 status_ = aos::starter::State::STOPPED;
317
318 // Disable force stop timer since the process already died
319 stop_timer_->Disable();
320
Austin Schuhfc304942021-10-16 14:20:05 -0700321 on_change_();
Tyler Chatowa79419d2020-08-12 20:12:11 -0700322 if (terminating_) {
323 return true;
324 }
325
326 if (queue_restart_) {
327 queue_restart_ = false;
328 status_ = aos::starter::State::WAITING;
329 DoStart();
330 }
331 break;
332 }
333 case aos::starter::State::WAITING:
334 case aos::starter::State::STOPPED: {
335 LOG(FATAL)
Austin Schuh3204b332021-10-16 14:20:10 -0700336 << "Received signal on process that was already stopped : name: '"
337 << name_ << "' pid: " << pid_;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700338 break;
339 }
340 }
341
342 return false;
343}
344
345ScopedPipe::ScopedPipe(int fd) : fd_(fd) {}
346
347ScopedPipe::~ScopedPipe() {
348 if (fd_ != -1) {
349 PCHECK(close(fd_) != -1);
350 }
351}
352
353ScopedPipe::ScopedPipe(ScopedPipe &&scoped_pipe) : fd_(scoped_pipe.fd_) {
354 scoped_pipe.fd_ = -1;
355}
356
357ScopedPipe &ScopedPipe::operator=(ScopedPipe &&scoped_pipe) {
358 if (fd_ != -1) {
359 PCHECK(close(fd_) != -1);
360 }
361 fd_ = scoped_pipe.fd_;
362 scoped_pipe.fd_ = -1;
363 return *this;
364}
365
366std::tuple<ScopedPipe::ScopedReadPipe, ScopedPipe::ScopedWritePipe>
367ScopedPipe::MakePipe() {
368 int fds[2];
369 PCHECK(pipe(fds) != -1);
370 PCHECK(fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK) != -1);
371 PCHECK(fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK) != -1);
372 return {ScopedReadPipe(fds[0]), ScopedWritePipe(fds[1])};
373}
374
375std::optional<uint32_t> ScopedPipe::ScopedReadPipe::Read() {
376 uint32_t buf;
377 ssize_t result = read(fd(), &buf, sizeof(buf));
378 if (result == sizeof(buf)) {
379 return buf;
380 } else {
381 return std::nullopt;
382 }
383}
384
385void ScopedPipe::ScopedWritePipe::Write(uint32_t data) {
386 ssize_t result = write(fd(), &data, sizeof(data));
387 PCHECK(result != -1);
388 CHECK(result == sizeof(data));
389}
390
391SignalListener::SignalListener(aos::ShmEventLoop *loop,
392 std::function<void(signalfd_siginfo)> callback)
393 : loop_(loop),
394 callback_(std::move(callback)),
395 signalfd_({SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGFPE, SIGSEGV, SIGPIPE,
396 SIGTERM, SIGBUS, SIGXCPU, SIGCHLD}) {
397 loop->epoll()->OnReadable(signalfd_.fd(), [this] {
398 signalfd_siginfo info = signalfd_.Read();
399
400 if (info.ssi_signo == 0) {
401 LOG(WARNING) << "Could not read " << sizeof(signalfd_siginfo) << " bytes";
402 return;
403 }
404
405 callback_(info);
406 });
407}
408
409SignalListener::~SignalListener() { loop_->epoll()->DeleteFd(signalfd_.fd()); }
410
James Kuszmaul293b2172021-11-10 16:20:48 -0800411const aos::Channel *StatusChannelForNode(const aos::Configuration *config,
412 const aos::Node *node) {
413 return configuration::GetChannel<Status>(config, "/aos", "", node);
414}
415const aos::Channel *StarterRpcChannelForNode(const aos::Configuration *config,
416 const aos::Node *node) {
417 return configuration::GetChannel<StarterRpc>(config, "/aos", "", node);
418}
419
Tyler Chatowa79419d2020-08-12 20:12:11 -0700420Starter::Starter(const aos::Configuration *event_loop_config)
421 : config_msg_(event_loop_config),
422 event_loop_(event_loop_config),
423 status_sender_(event_loop_.MakeSender<aos::starter::Status>("/aos")),
Austin Schuhfc304942021-10-16 14:20:05 -0700424 status_timer_(event_loop_.AddTimer([this] {
425 SendStatus();
426 status_count_ = 0;
427 })),
Tyler Chatowa79419d2020-08-12 20:12:11 -0700428 cleanup_timer_(event_loop_.AddTimer([this] { event_loop_.Exit(); })),
Austin Schuhfc304942021-10-16 14:20:05 -0700429 max_status_count_(
430 event_loop_.GetChannel<aos::starter::Status>("/aos")->frequency() -
431 1),
Tyler Chatowa79419d2020-08-12 20:12:11 -0700432 listener_(&event_loop_,
433 [this](signalfd_siginfo signal) { OnSignal(signal); }) {
Tyler Chatowa79419d2020-08-12 20:12:11 -0700434 event_loop_.SkipAosLog();
435
436 event_loop_.OnRun([this] {
437 status_timer_->Setup(event_loop_.monotonic_now(),
Austin Schuhfc304942021-10-16 14:20:05 -0700438 std::chrono::milliseconds(1000));
Tyler Chatowa79419d2020-08-12 20:12:11 -0700439 });
440
James Kuszmaul293b2172021-11-10 16:20:48 -0800441 if (!aos::configuration::MultiNode(config_msg_)) {
442 event_loop_.MakeWatcher(
443 "/aos",
444 [this](const aos::starter::StarterRpc &cmd) { HandleStarterRpc(cmd); });
445 } else {
446 for (const aos::Node *node : aos::configuration::GetNodes(config_msg_)) {
447 const Channel *channel = StarterRpcChannelForNode(config_msg_, node);
448 CHECK(channel != nullptr) << ": Failed to find channel /aos for "
449 << StarterRpc::GetFullyQualifiedName() << " on "
450 << node->name()->string_view();
451 if (!aos::configuration::ChannelIsReadableOnNode(channel,
452 event_loop_.node())) {
453 LOG(INFO) << "StarterRpc channel "
454 << aos::configuration::StrippedChannelToString(channel)
455 << " is not readable on "
456 << event_loop_.node()->name()->string_view();
457 } else {
458 event_loop_.MakeWatcher(channel->name()->string_view(),
459 [this](const aos::starter::StarterRpc &cmd) {
460 HandleStarterRpc(cmd);
461 });
462 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700463 }
James Kuszmaul293b2172021-11-10 16:20:48 -0800464 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700465
466 if (config_msg_->has_applications()) {
467 const flatbuffers::Vector<flatbuffers::Offset<aos::Application>>
468 *applications = config_msg_->applications();
Ravago Jones7e2dd322020-11-21 15:58:58 -0800469
470 if (aos::configuration::MultiNode(config_msg_)) {
471 std::string_view current_node = event_loop_.node()->name()->string_view();
472 for (const aos::Application *application : *applications) {
473 CHECK(application->has_nodes());
474 for (const flatbuffers::String *node : *application->nodes()) {
475 if (node->string_view() == current_node) {
476 AddApplication(application);
477 break;
478 }
479 }
480 }
481 } else {
482 for (const aos::Application *application : *applications) {
483 AddApplication(application);
484 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700485 }
486 }
487}
488
James Kuszmaul293b2172021-11-10 16:20:48 -0800489void Starter::HandleStarterRpc(const StarterRpc &command) {
490 if (!command.has_command() || !command.has_name() || exiting_) {
491 return;
492 }
493
494 LOG(INFO) << "Received " << aos::FlatbufferToJson(&command);
495
496 if (command.has_nodes()) {
497 CHECK(aos::configuration::MultiNode(config_msg_));
498 bool relevant_to_this_node = false;
499 for (const flatbuffers::String *node : *command.nodes()) {
500 if (node->string_view() == event_loop_.node()->name()->string_view()) {
501 relevant_to_this_node = true;
502 }
503 }
504 if (!relevant_to_this_node) {
505 return;
506 }
507 }
508 // If not populated, restart regardless of node.
509
510 auto search = applications_.find(command.name()->str());
511 if (search != applications_.end()) {
512 // If an applicatione exists by the given name, dispatch the command
513 search->second.HandleCommand(command.command());
514 }
515}
516
Austin Schuhfc304942021-10-16 14:20:05 -0700517void Starter::MaybeSendStatus() {
518 if (status_count_ < max_status_count_) {
519 SendStatus();
520 ++status_count_;
521 } else {
522 VLOG(1) << "That's enough " << status_count_ << " " << max_status_count_;
523 }
524}
525
Tyler Chatowa79419d2020-08-12 20:12:11 -0700526void Starter::Cleanup() {
527 if (exiting_) {
528 return;
529 }
530 exiting_ = true;
531 for (auto &application : applications_) {
532 application.second.Terminate();
533 }
534 cleanup_timer_->Setup(event_loop_.monotonic_now() +
535 std::chrono::milliseconds(1500));
536}
537
538void Starter::OnSignal(signalfd_siginfo info) {
Tyler Chatowa79419d2020-08-12 20:12:11 -0700539 if (info.ssi_signo == SIGCHLD) {
540 // SIGCHLD messages can be collapsed if multiple are received, so all
541 // applications must check their status.
542 for (auto iter = applications_.begin(); iter != applications_.end();) {
543 if (iter->second.MaybeHandleSignal()) {
544 iter = applications_.erase(iter);
545 } else {
546 ++iter;
547 }
548 }
549
550 if (exiting_ && applications_.empty()) {
551 event_loop_.Exit();
552 }
Austin Schuh3204b332021-10-16 14:20:10 -0700553 } else {
554 LOG(INFO) << "Received signal '" << strsignal(info.ssi_signo) << "'";
555
556 if (std::find(kStarterDeath.begin(), kStarterDeath.end(), info.ssi_signo) !=
557 kStarterDeath.end()) {
558 LOG(WARNING) << "Starter shutting down";
559 Cleanup();
560 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700561 }
562}
563
564Application *Starter::AddApplication(const aos::Application *application) {
Austin Schuhfc304942021-10-16 14:20:05 -0700565 auto [iter, success] =
566 applications_.try_emplace(application->name()->str(), application,
567 &event_loop_, [this]() { MaybeSendStatus(); });
Tyler Chatowa79419d2020-08-12 20:12:11 -0700568 if (success) {
569 if (application->has_args()) {
570 iter->second.set_args(*application->args());
571 }
572 return &(iter->second);
573 }
574 return nullptr;
575}
576
577void Starter::Run() {
Tyler Chatow03fdb2a2020-12-26 18:39:36 -0800578#ifdef AOS_ARCHITECTURE_arm_frc
579 PCHECK(setuid(0) == 0) << "Failed to change user to root";
580#endif
581
Tyler Chatowa79419d2020-08-12 20:12:11 -0700582 for (auto &application : applications_) {
Austin Schuh5f79a5a2021-10-12 17:46:50 -0700583 if (application.second.autostart()) {
584 application.second.Start();
585 }
Tyler Chatowa79419d2020-08-12 20:12:11 -0700586 }
587
588 event_loop_.Run();
589}
590
591void Starter::SendStatus() {
592 aos::Sender<aos::starter::Status>::Builder builder =
593 status_sender_.MakeBuilder();
594
595 std::vector<flatbuffers::Offset<aos::starter::ApplicationStatus>> statuses;
596
597 for (auto &application : applications_) {
598 statuses.push_back(application.second.PopulateStatus(builder.fbb()));
599 }
600
601 auto statuses_fbs = builder.fbb()->CreateVector(statuses);
602
603 aos::starter::Status::Builder status_builder(*builder.fbb());
604 status_builder.add_statuses(statuses_fbs);
605 CHECK(builder.Send(status_builder.Finish()));
606}
607
608} // namespace starter
609} // namespace aos