• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 <arpa/inet.h>
18 #include <cutils/sockets.h>
19 #include <errno.h>
20 #include <netinet/in.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include <android-base/cmsg.h>
29 #include <android-base/logging.h>
30 #include <android-base/properties.h>
31 #include <android-base/scopeguard.h>
32 #include <fs_mgr/file_wait.h>
33 #include <snapuserd/snapuserd_client.h>
34 #include "snapuserd_server.h"
35 
36 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
37 #include <sys/_system_properties.h>
38 
39 namespace android {
40 namespace snapshot {
41 
42 using namespace std::string_literals;
43 
44 using android::base::borrowed_fd;
45 using android::base::unique_fd;
46 
Resolveop(std::string & input)47 DaemonOps UserSnapshotServer::Resolveop(std::string& input) {
48     if (input == "init") return DaemonOps::INIT;
49     if (input == "start") return DaemonOps::START;
50     if (input == "stop") return DaemonOps::STOP;
51     if (input == "query") return DaemonOps::QUERY;
52     if (input == "delete") return DaemonOps::DELETE;
53     if (input == "detach") return DaemonOps::DETACH;
54     if (input == "supports") return DaemonOps::SUPPORTS;
55     if (input == "initiate_merge") return DaemonOps::INITIATE;
56     if (input == "merge_percent") return DaemonOps::PERCENTAGE;
57     if (input == "getstatus") return DaemonOps::GETSTATUS;
58     if (input == "update-verify") return DaemonOps::UPDATE_VERIFY;
59 
60     return DaemonOps::INVALID;
61 }
62 
UserSnapshotServer()63 UserSnapshotServer::UserSnapshotServer() {
64     monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC));
65     if (monitor_merge_event_fd_ == -1) {
66         PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd";
67     }
68     terminating_ = false;
69 }
70 
~UserSnapshotServer()71 UserSnapshotServer::~UserSnapshotServer() {
72     // Close any client sockets that were added via AcceptClient().
73     for (size_t i = 1; i < watched_fds_.size(); i++) {
74         close(watched_fds_[i].fd);
75     }
76 }
77 
GetDaemonStatus()78 std::string UserSnapshotServer::GetDaemonStatus() {
79     std::string msg = "";
80 
81     if (IsTerminating())
82         msg = "passive";
83     else
84         msg = "active";
85 
86     return msg;
87 }
88 
Parsemsg(std::string const & msg,const char delim,std::vector<std::string> & out)89 void UserSnapshotServer::Parsemsg(std::string const& msg, const char delim,
90                                   std::vector<std::string>& out) {
91     std::stringstream ss(msg);
92     std::string s;
93 
94     while (std::getline(ss, s, delim)) {
95         out.push_back(s);
96     }
97 }
98 
ShutdownThreads()99 void UserSnapshotServer::ShutdownThreads() {
100     terminating_ = true;
101     JoinAllThreads();
102 }
103 
UserSnapshotDmUserHandler(std::shared_ptr<SnapshotHandler> snapuserd)104 UserSnapshotDmUserHandler::UserSnapshotDmUserHandler(std::shared_ptr<SnapshotHandler> snapuserd)
105     : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
106 
Sendmsg(android::base::borrowed_fd fd,const std::string & msg)107 bool UserSnapshotServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
108     ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), MSG_NOSIGNAL));
109     if (ret < 0) {
110         PLOG(ERROR) << "Snapuserd:server: send() failed";
111         return false;
112     }
113 
114     if (ret < msg.size()) {
115         LOG(ERROR) << "Partial send; expected " << msg.size() << " bytes, sent " << ret;
116         return false;
117     }
118     return true;
119 }
120 
Recv(android::base::borrowed_fd fd,std::string * data)121 bool UserSnapshotServer::Recv(android::base::borrowed_fd fd, std::string* data) {
122     char msg[kMaxPacketSize];
123     ssize_t rv = TEMP_FAILURE_RETRY(recv(fd.get(), msg, sizeof(msg), 0));
124     if (rv < 0) {
125         PLOG(ERROR) << "recv failed";
126         return false;
127     }
128     *data = std::string(msg, rv);
129     return true;
130 }
131 
Receivemsg(android::base::borrowed_fd fd,const std::string & str)132 bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::string& str) {
133     const char delim = ',';
134 
135     std::vector<std::string> out;
136     Parsemsg(str, delim, out);
137     DaemonOps op = Resolveop(out[0]);
138 
139     switch (op) {
140         case DaemonOps::INIT: {
141             // Message format:
142             // init,<misc_name>,<cow_device_path>,<backing_device>,<base_path_merge>
143             //
144             // Reads the metadata and send the number of sectors
145             if (out.size() != 5) {
146                 LOG(ERROR) << "Malformed init message, " << out.size() << " parts";
147                 return Sendmsg(fd, "fail");
148             }
149 
150             auto handler = AddHandler(out[1], out[2], out[3], out[4]);
151             if (!handler) {
152                 return Sendmsg(fd, "fail");
153             }
154 
155             auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
156             return Sendmsg(fd, retval);
157         }
158         case DaemonOps::START: {
159             // Message format:
160             // start,<misc_name>
161             //
162             // Start the new thread which binds to dm-user misc device
163             if (out.size() != 2) {
164                 LOG(ERROR) << "Malformed start message, " << out.size() << " parts";
165                 return Sendmsg(fd, "fail");
166             }
167 
168             std::lock_guard<std::mutex> lock(lock_);
169             auto iter = FindHandler(&lock, out[1]);
170             if (iter == dm_users_.end()) {
171                 LOG(ERROR) << "Could not find handler: " << out[1];
172                 return Sendmsg(fd, "fail");
173             }
174             if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) {
175                 LOG(ERROR) << "Tried to re-attach control device: " << out[1];
176                 return Sendmsg(fd, "fail");
177             }
178             if (!StartHandler(*iter)) {
179                 return Sendmsg(fd, "fail");
180             }
181             return Sendmsg(fd, "success");
182         }
183         case DaemonOps::STOP: {
184             // Message format: stop
185             //
186             // Stop all the threads gracefully and then shutdown the
187             // main thread
188             SetTerminating();
189             ShutdownThreads();
190             return true;
191         }
192         case DaemonOps::QUERY: {
193             // Message format: query
194             //
195             // As part of transition, Second stage daemon will be
196             // created before terminating the first stage daemon. Hence,
197             // for a brief period client may have to distiguish between
198             // first stage daemon and second stage daemon.
199             //
200             // Second stage daemon is marked as active and hence will
201             // be ready to receive control message.
202             return Sendmsg(fd, GetDaemonStatus());
203         }
204         case DaemonOps::DELETE: {
205             // Message format:
206             // delete,<misc_name>
207             if (out.size() != 2) {
208                 LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
209                 return Sendmsg(fd, "fail");
210             }
211             {
212                 std::lock_guard<std::mutex> lock(lock_);
213                 auto iter = FindHandler(&lock, out[1]);
214                 if (iter == dm_users_.end()) {
215                     // After merge is completed, we swap dm-user table with
216                     // the underlying dm-linear base device. Hence, worker
217                     // threads would have terminted and was removed from
218                     // the list.
219                     LOG(DEBUG) << "Could not find handler: " << out[1];
220                     return Sendmsg(fd, "success");
221                 }
222 
223                 if (!(*iter)->ThreadTerminated()) {
224                     (*iter)->snapuserd()->NotifyIOTerminated();
225                 }
226             }
227             if (!RemoveAndJoinHandler(out[1])) {
228                 return Sendmsg(fd, "fail");
229             }
230             return Sendmsg(fd, "success");
231         }
232         case DaemonOps::DETACH: {
233             std::lock_guard<std::mutex> lock(lock_);
234             TerminateMergeThreads(&lock);
235             terminating_ = true;
236             return true;
237         }
238         case DaemonOps::SUPPORTS: {
239             if (out.size() != 2) {
240                 LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
241                 return Sendmsg(fd, "fail");
242             }
243             if (out[1] == "second_stage_socket_handoff") {
244                 return Sendmsg(fd, "success");
245             }
246             return Sendmsg(fd, "fail");
247         }
248         case DaemonOps::INITIATE: {
249             if (out.size() != 2) {
250                 LOG(ERROR) << "Malformed initiate-merge message, " << out.size() << " parts";
251                 return Sendmsg(fd, "fail");
252             }
253             if (out[0] == "initiate_merge") {
254                 std::lock_guard<std::mutex> lock(lock_);
255                 auto iter = FindHandler(&lock, out[1]);
256                 if (iter == dm_users_.end()) {
257                     LOG(ERROR) << "Could not find handler: " << out[1];
258                     return Sendmsg(fd, "fail");
259                 }
260 
261                 if (!StartMerge(&lock, *iter)) {
262                     return Sendmsg(fd, "fail");
263                 }
264 
265                 return Sendmsg(fd, "success");
266             }
267             return Sendmsg(fd, "fail");
268         }
269         case DaemonOps::PERCENTAGE: {
270             std::lock_guard<std::mutex> lock(lock_);
271             double percentage = GetMergePercentage(&lock);
272 
273             return Sendmsg(fd, std::to_string(percentage));
274         }
275         case DaemonOps::GETSTATUS: {
276             // Message format:
277             // getstatus,<misc_name>
278             if (out.size() != 2) {
279                 LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
280                 return Sendmsg(fd, "snapshot-merge-failed");
281             }
282             {
283                 std::lock_guard<std::mutex> lock(lock_);
284                 auto iter = FindHandler(&lock, out[1]);
285                 if (iter == dm_users_.end()) {
286                     LOG(ERROR) << "Could not find handler: " << out[1];
287                     return Sendmsg(fd, "snapshot-merge-failed");
288                 }
289 
290                 std::string merge_status = GetMergeStatus(*iter);
291                 return Sendmsg(fd, merge_status);
292             }
293         }
294         case DaemonOps::UPDATE_VERIFY: {
295             std::lock_guard<std::mutex> lock(lock_);
296             if (!UpdateVerification(&lock)) {
297                 return Sendmsg(fd, "fail");
298             }
299 
300             return Sendmsg(fd, "success");
301         }
302         default: {
303             LOG(ERROR) << "Received unknown message type from client";
304             Sendmsg(fd, "fail");
305             return false;
306         }
307     }
308 }
309 
RunThread(std::shared_ptr<UserSnapshotDmUserHandler> handler)310 void UserSnapshotServer::RunThread(std::shared_ptr<UserSnapshotDmUserHandler> handler) {
311     LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
312 
313     if (!handler->snapuserd()->Start()) {
314         LOG(ERROR) << " Failed to launch all worker threads";
315     }
316 
317     handler->snapuserd()->CloseFds();
318     bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus();
319     handler->snapuserd()->UnmapBufferRegion();
320 
321     auto misc_name = handler->misc_name();
322     LOG(INFO) << "Handler thread about to exit: " << misc_name;
323 
324     {
325         std::lock_guard<std::mutex> lock(lock_);
326         if (merge_completed) {
327             num_partitions_merge_complete_ += 1;
328             active_merge_threads_ -= 1;
329             WakeupMonitorMergeThread();
330         }
331         handler->SetThreadTerminated();
332         auto iter = FindHandler(&lock, handler->misc_name());
333         if (iter == dm_users_.end()) {
334             // RemoveAndJoinHandler() already removed us from the list, and is
335             // now waiting on a join(), so just return. Additionally, release
336             // all the resources held by snapuserd object which are shared
337             // by worker threads. This should be done when the last reference
338             // of "handler" is released; but we will explicitly release here
339             // to make sure snapuserd object is freed as it is the biggest
340             // consumer of memory in the daemon.
341             handler->FreeResources();
342             LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
343             return;
344         }
345 
346         LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name;
347 
348         if (handler->snapuserd()->IsAttached()) {
349             handler->thread().detach();
350         }
351 
352         // Important: free resources within the lock. This ensures that if
353         // WaitForDelete() is called, the handler is either in the list, or
354         // it's not and its resources are guaranteed to be freed.
355         handler->FreeResources();
356         dm_users_.erase(iter);
357     }
358 }
359 
Start(const std::string & socketname)360 bool UserSnapshotServer::Start(const std::string& socketname) {
361     bool start_listening = true;
362 
363     sockfd_.reset(android_get_control_socket(socketname.c_str()));
364     if (sockfd_ < 0) {
365         sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
366                                           SOCK_STREAM));
367         if (sockfd_ < 0) {
368             PLOG(ERROR) << "Failed to create server socket " << socketname;
369             return false;
370         }
371         start_listening = false;
372     }
373     return StartWithSocket(start_listening);
374 }
375 
StartWithSocket(bool start_listening)376 bool UserSnapshotServer::StartWithSocket(bool start_listening) {
377     if (start_listening && listen(sockfd_.get(), 4) < 0) {
378         PLOG(ERROR) << "listen socket failed";
379         return false;
380     }
381 
382     AddWatchedFd(sockfd_, POLLIN);
383     is_socket_present_ = true;
384 
385     // If started in first-stage init, the property service won't be online.
386     if (access("/dev/socket/property_service", F_OK) == 0) {
387         if (!android::base::SetProperty("snapuserd.ready", "true")) {
388             LOG(ERROR) << "Failed to set snapuserd.ready property";
389             return false;
390         }
391     }
392 
393     LOG(DEBUG) << "Snapuserd server now accepting connections";
394     return true;
395 }
396 
Run()397 bool UserSnapshotServer::Run() {
398     LOG(INFO) << "Now listening on snapuserd socket";
399 
400     while (!IsTerminating()) {
401         int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
402         if (rv < 0) {
403             PLOG(ERROR) << "poll failed";
404             return false;
405         }
406         if (!rv) {
407             continue;
408         }
409 
410         if (watched_fds_[0].revents) {
411             AcceptClient();
412         }
413 
414         auto iter = watched_fds_.begin() + 1;
415         while (iter != watched_fds_.end()) {
416             if (iter->revents && !HandleClient(iter->fd, iter->revents)) {
417                 close(iter->fd);
418                 iter = watched_fds_.erase(iter);
419             } else {
420                 iter++;
421             }
422         }
423     }
424 
425     JoinAllThreads();
426     return true;
427 }
428 
JoinAllThreads()429 void UserSnapshotServer::JoinAllThreads() {
430     // Acquire the thread list within the lock.
431     std::vector<std::shared_ptr<UserSnapshotDmUserHandler>> dm_users;
432     {
433         std::lock_guard<std::mutex> guard(lock_);
434         dm_users = std::move(dm_users_);
435     }
436 
437     for (auto& client : dm_users) {
438         auto& th = client->thread();
439 
440         if (th.joinable()) th.join();
441     }
442 
443     stop_monitor_merge_thread_ = true;
444     WakeupMonitorMergeThread();
445 }
446 
AddWatchedFd(android::base::borrowed_fd fd,int events)447 void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
448     struct pollfd p = {};
449     p.fd = fd.get();
450     p.events = events;
451     watched_fds_.emplace_back(std::move(p));
452 }
453 
AcceptClient()454 void UserSnapshotServer::AcceptClient() {
455     int fd = TEMP_FAILURE_RETRY(accept4(sockfd_.get(), nullptr, nullptr, SOCK_CLOEXEC));
456     if (fd < 0) {
457         PLOG(ERROR) << "accept4 failed";
458         return;
459     }
460 
461     AddWatchedFd(fd, POLLIN);
462 }
463 
HandleClient(android::base::borrowed_fd fd,int revents)464 bool UserSnapshotServer::HandleClient(android::base::borrowed_fd fd, int revents) {
465     if (revents & POLLHUP) {
466         LOG(DEBUG) << "Snapuserd client disconnected";
467         return false;
468     }
469 
470     std::string str;
471     if (!Recv(fd, &str)) {
472         return false;
473     }
474     if (!Receivemsg(fd, str)) {
475         LOG(ERROR) << "Encountered error handling client message, revents: " << revents;
476         return false;
477     }
478     return true;
479 }
480 
Interrupt()481 void UserSnapshotServer::Interrupt() {
482     // Force close the socket so poll() fails.
483     sockfd_ = {};
484     SetTerminating();
485 }
486 
AddHandler(const std::string & misc_name,const std::string & cow_device_path,const std::string & backing_device,const std::string & base_path_merge)487 std::shared_ptr<UserSnapshotDmUserHandler> UserSnapshotServer::AddHandler(
488         const std::string& misc_name, const std::string& cow_device_path,
489         const std::string& backing_device, const std::string& base_path_merge) {
490     auto snapuserd = std::make_shared<SnapshotHandler>(misc_name, cow_device_path, backing_device,
491                                                        base_path_merge);
492     if (!snapuserd->InitCowDevice()) {
493         LOG(ERROR) << "Failed to initialize Snapuserd";
494         return nullptr;
495     }
496 
497     snapuserd->SetSocketPresent(is_socket_present_);
498     snapuserd->SetIouringEnabled(io_uring_enabled_);
499 
500     if (!snapuserd->InitializeWorkers()) {
501         LOG(ERROR) << "Failed to initialize workers";
502         return nullptr;
503     }
504 
505     auto handler = std::make_shared<UserSnapshotDmUserHandler>(snapuserd);
506     {
507         std::lock_guard<std::mutex> lock(lock_);
508         if (FindHandler(&lock, misc_name) != dm_users_.end()) {
509             LOG(ERROR) << "Handler already exists: " << misc_name;
510             return nullptr;
511         }
512         dm_users_.push_back(handler);
513     }
514     return handler;
515 }
516 
StartHandler(const std::shared_ptr<UserSnapshotDmUserHandler> & handler)517 bool UserSnapshotServer::StartHandler(const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
518     if (handler->snapuserd()->IsAttached()) {
519         LOG(ERROR) << "Handler already attached";
520         return false;
521     }
522 
523     handler->snapuserd()->AttachControlDevice();
524 
525     handler->thread() = std::thread(std::bind(&UserSnapshotServer::RunThread, this, handler));
526     return true;
527 }
528 
StartMerge(std::lock_guard<std::mutex> * proof_of_lock,const std::shared_ptr<UserSnapshotDmUserHandler> & handler)529 bool UserSnapshotServer::StartMerge(std::lock_guard<std::mutex>* proof_of_lock,
530                                     const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
531     CHECK(proof_of_lock);
532 
533     if (!handler->snapuserd()->IsAttached()) {
534         LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started";
535         return false;
536     }
537 
538     handler->snapuserd()->MonitorMerge();
539 
540     if (!is_merge_monitor_started_.has_value()) {
541         std::thread(&UserSnapshotServer::MonitorMerge, this).detach();
542         is_merge_monitor_started_ = true;
543     }
544 
545     merge_handlers_.push(handler);
546     WakeupMonitorMergeThread();
547     return true;
548 }
549 
FindHandler(std::lock_guard<std::mutex> * proof_of_lock,const std::string & misc_name)550 auto UserSnapshotServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
551                                      const std::string& misc_name) -> HandlerList::iterator {
552     CHECK(proof_of_lock);
553 
554     for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
555         if ((*iter)->misc_name() == misc_name) {
556             return iter;
557         }
558     }
559     return dm_users_.end();
560 }
561 
TerminateMergeThreads(std::lock_guard<std::mutex> * proof_of_lock)562 void UserSnapshotServer::TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock) {
563     CHECK(proof_of_lock);
564 
565     for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
566         if (!(*iter)->ThreadTerminated()) {
567             (*iter)->snapuserd()->NotifyIOTerminated();
568         }
569     }
570 }
571 
GetMergeStatus(const std::shared_ptr<UserSnapshotDmUserHandler> & handler)572 std::string UserSnapshotServer::GetMergeStatus(
573         const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
574     return handler->snapuserd()->GetMergeStatus();
575 }
576 
GetMergePercentage(std::lock_guard<std::mutex> * proof_of_lock)577 double UserSnapshotServer::GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock) {
578     CHECK(proof_of_lock);
579     double percentage = 0.0;
580     int n = 0;
581 
582     for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
583         auto& th = (*iter)->thread();
584         if (th.joinable()) {
585             // Merge percentage by individual partitions wherein merge is still
586             // in-progress
587             percentage += (*iter)->snapuserd()->GetMergePercentage();
588             n += 1;
589         }
590     }
591 
592     // Calculate final merge including those partitions where merge was already
593     // completed - num_partitions_merge_complete_ will track them when each
594     // thread exists in RunThread.
595     int total_partitions = n + num_partitions_merge_complete_;
596 
597     if (total_partitions) {
598         percentage = ((num_partitions_merge_complete_ * 100.0) + percentage) / total_partitions;
599     }
600 
601     LOG(DEBUG) << "Merge %: " << percentage
602                << " num_partitions_merge_complete_: " << num_partitions_merge_complete_
603                << " total_partitions: " << total_partitions << " n: " << n;
604     return percentage;
605 }
606 
RemoveAndJoinHandler(const std::string & misc_name)607 bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) {
608     std::shared_ptr<UserSnapshotDmUserHandler> handler;
609     {
610         std::lock_guard<std::mutex> lock(lock_);
611 
612         auto iter = FindHandler(&lock, misc_name);
613         if (iter == dm_users_.end()) {
614             // Client already deleted.
615             return true;
616         }
617         handler = std::move(*iter);
618         dm_users_.erase(iter);
619     }
620 
621     auto& th = handler->thread();
622     if (th.joinable()) {
623         th.join();
624     }
625     return true;
626 }
627 
WakeupMonitorMergeThread()628 void UserSnapshotServer::WakeupMonitorMergeThread() {
629     uint64_t notify = 1;
630     ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), &notify, sizeof(notify)));
631     if (rc < 0) {
632         PLOG(FATAL) << "failed to notify monitor merge thread";
633     }
634 }
635 
MonitorMerge()636 void UserSnapshotServer::MonitorMerge() {
637     while (!stop_monitor_merge_thread_) {
638         uint64_t testVal;
639         ssize_t ret =
640                 TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal)));
641         if (ret == -1) {
642             PLOG(FATAL) << "Failed to read from eventfd";
643         } else if (ret == 0) {
644             LOG(FATAL) << "Hit EOF on eventfd";
645         }
646 
647         LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_;
648         {
649             std::lock_guard<std::mutex> lock(lock_);
650             while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) {
651                 auto handler = merge_handlers_.front();
652                 merge_handlers_.pop();
653                 LOG(INFO) << "Starting merge for partition: "
654                           << handler->snapuserd()->GetMiscName();
655                 handler->snapuserd()->InitiateMerge();
656                 active_merge_threads_ += 1;
657             }
658         }
659     }
660 
661     LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size();
662 }
663 
WaitForSocket()664 bool UserSnapshotServer::WaitForSocket() {
665     auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
666 
667     auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
668 
669     if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
670         LOG(ERROR)
671                 << "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
672         return false;
673     }
674 
675     // This initialization of system property is important. When daemon is
676     // launched post selinux transition (before init second stage),
677     // bionic libc initializes system property as part of __libc_init_common();
678     // however that initialization fails silently given that fact that we don't
679     // have /dev/__properties__ setup which is created at init second stage.
680     //
681     // At this point, we have the handlers setup and is safe to setup property.
682     __system_properties_init();
683 
684     if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
685         LOG(ERROR)
686                 << "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
687         return false;
688     }
689 
690     unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
691                                      SOCK_SEQPACKET));
692     if (fd < 0) {
693         PLOG(ERROR) << "Failed to connect to socket proxy";
694         return false;
695     }
696 
697     char code[1];
698     std::vector<unique_fd> fds;
699     ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
700     if (rv < 0) {
701         PLOG(ERROR) << "Failed to receive server socket over proxy";
702         return false;
703     }
704     if (fds.empty()) {
705         LOG(ERROR) << "Expected at least one file descriptor from proxy";
706         return false;
707     }
708 
709     // We don't care if the ACK is received.
710     code[0] = 'a';
711     if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
712         PLOG(ERROR) << "Failed to send ACK to proxy";
713         return false;
714     }
715 
716     sockfd_ = std::move(fds[0]);
717     if (!StartWithSocket(true)) {
718         return false;
719     }
720 
721     return Run();
722 }
723 
RunForSocketHandoff()724 bool UserSnapshotServer::RunForSocketHandoff() {
725     unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
726     if (proxy_fd < 0) {
727         PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
728     }
729     borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
730     if (server_fd < 0) {
731         PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
732     }
733 
734     if (listen(proxy_fd.get(), 4) < 0) {
735         PLOG(FATAL) << "Proxy listen socket failed";
736     }
737 
738     if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
739         LOG(FATAL) << "Proxy failed to set ready property";
740     }
741 
742     unique_fd client_fd(
743             TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
744     if (client_fd < 0) {
745         PLOG(FATAL) << "Proxy accept failed";
746     }
747 
748     char code[1] = {'a'};
749     std::vector<int> fds = {server_fd.get()};
750     ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
751     if (rv < 0) {
752         PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
753     }
754     // Wait for an ACK - results don't matter, we just don't want to risk closing
755     // the proxy socket too early.
756     if (recv(client_fd, code, sizeof(code), 0) < 0) {
757         PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
758     }
759     return true;
760 }
761 
UpdateVerification(std::lock_guard<std::mutex> * proof_of_lock)762 bool UserSnapshotServer::UpdateVerification(std::lock_guard<std::mutex>* proof_of_lock) {
763     CHECK(proof_of_lock);
764 
765     bool status = true;
766     for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
767         auto& th = (*iter)->thread();
768         if (th.joinable() && status) {
769             status = (*iter)->snapuserd()->CheckPartitionVerification() && status;
770         } else {
771             // return immediately if there is a failure
772             return false;
773         }
774     }
775 
776     return status;
777 }
778 
779 }  // namespace snapshot
780 }  // namespace android
781