• 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 <netdb.h>
21 #include <netinet/in.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
29 #include <chrono>
30 #include <sstream>
31 
32 #include <android-base/logging.h>
33 #include <android-base/parseint.h>
34 #include <android-base/properties.h>
35 #include <android-base/strings.h>
36 #include <snapuserd/snapuserd_client.h>
37 
38 namespace android {
39 namespace snapshot {
40 
41 using namespace std::chrono_literals;
42 using android::base::unique_fd;
43 
EnsureSnapuserdStarted()44 bool EnsureSnapuserdStarted() {
45     if (android::base::GetProperty("init.svc.snapuserd", "") != "running") {
46         android::base::SetProperty("ctl.start", "snapuserd");
47         if (!android::base::WaitForProperty("init.svc.snapuserd", "running", 10s)) {
48             LOG(ERROR) << "Timed out waiting for snapuserd to start.";
49             return false;
50         }
51     }
52     if (!android::base::WaitForProperty("snapuserd.ready", "true", 10s)) {
53         LOG(ERROR) << "Timed out waiting for snapuserd to be ready.";
54         return false;
55     }
56     return true;
57 }
58 
SnapuserdClient(android::base::unique_fd && sockfd)59 SnapuserdClient::SnapuserdClient(android::base::unique_fd&& sockfd) : sockfd_(std::move(sockfd)) {}
60 
IsRetryErrno()61 static inline bool IsRetryErrno() {
62     return errno == ECONNREFUSED || errno == EINTR || errno == ENOENT;
63 }
64 
Connect(const std::string & socket_name,std::chrono::milliseconds timeout_ms)65 std::unique_ptr<SnapuserdClient> SnapuserdClient::Connect(const std::string& socket_name,
66                                                           std::chrono::milliseconds timeout_ms) {
67     unique_fd fd;
68     auto start = std::chrono::steady_clock::now();
69     while (true) {
70         fd.reset(socket_local_client(socket_name.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
71                                      SOCK_STREAM));
72         if (fd >= 0) break;
73         if (fd < 0 && !IsRetryErrno()) {
74             PLOG(ERROR) << "connect failed: " << socket_name;
75             return nullptr;
76         }
77 
78         auto now = std::chrono::steady_clock::now();
79         auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
80         if (elapsed >= timeout_ms) {
81             LOG(ERROR) << "Timed out connecting to snapuserd socket: " << socket_name;
82             return nullptr;
83         }
84 
85         std::this_thread::sleep_for(100ms);
86     }
87 
88     auto client = std::make_unique<SnapuserdClient>(std::move(fd));
89     if (!client->ValidateConnection()) {
90         return nullptr;
91     }
92     return client;
93 }
94 
ValidateConnection()95 bool SnapuserdClient::ValidateConnection() {
96     if (!Sendmsg("query")) {
97         return false;
98     }
99 
100     std::string str = Receivemsg();
101 
102     // If the daemon is passive then fallback to secondary active daemon. Daemon
103     // is passive during transition phase.
104     if (str.find("passive") != std::string::npos) {
105         LOG(ERROR) << "Snapuserd is terminating";
106         return false;
107     }
108 
109     if (str != "active") {
110         LOG(ERROR) << "Received failure querying daemon";
111         return false;
112     }
113     return true;
114 }
115 
Sendmsg(const std::string & msg)116 bool SnapuserdClient::Sendmsg(const std::string& msg) {
117     LOG(DEBUG) << "Sendmsg: msg " << msg << " sockfd: " << sockfd_;
118     ssize_t numBytesSent = TEMP_FAILURE_RETRY(send(sockfd_, msg.data(), msg.size(), MSG_NOSIGNAL));
119     if (numBytesSent < 0) {
120         PLOG(ERROR) << "Send failed";
121         return false;
122     }
123 
124     if ((size_t)numBytesSent < msg.size()) {
125         LOG(ERROR) << "Partial data sent, expected " << msg.size() << " bytes, sent "
126                    << numBytesSent;
127         return false;
128     }
129     return true;
130 }
131 
WaitForDeviceDelete(const std::string & control_device)132 bool SnapuserdClient::WaitForDeviceDelete(const std::string& control_device) {
133     std::string msg = "delete," + control_device;
134     if (!Sendmsg(msg)) {
135         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
136         return false;
137     }
138     std::string response = Receivemsg();
139     if (response != "success") {
140         LOG(ERROR) << "Failed waiting to delete device " << control_device;
141         return false;
142     }
143     return true;
144 }
145 
SupportsSecondStageSocketHandoff()146 bool SnapuserdClient::SupportsSecondStageSocketHandoff() {
147     std::string msg = "supports,second_stage_socket_handoff";
148     if (!Sendmsg(msg)) {
149         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
150         return false;
151     }
152     std::string response = Receivemsg();
153     return response == "success";
154 }
155 
Receivemsg()156 std::string SnapuserdClient::Receivemsg() {
157     char msg[PACKET_SIZE];
158     ssize_t ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, sizeof(msg), 0));
159     if (ret < 0) {
160         PLOG(ERROR) << "Snapuserd:client: recv failed";
161         return {};
162     }
163     if (ret == 0) {
164         LOG(DEBUG) << "Snapuserd:client disconnected";
165         return {};
166     }
167     return std::string(msg, ret);
168 }
169 
StopSnapuserd()170 bool SnapuserdClient::StopSnapuserd() {
171     if (!Sendmsg("stop")) {
172         LOG(ERROR) << "Failed to send stop message to snapuserd daemon";
173         return false;
174     }
175 
176     sockfd_ = {};
177     return true;
178 }
179 
AttachDmUser(const std::string & misc_name)180 bool SnapuserdClient::AttachDmUser(const std::string& misc_name) {
181     std::string msg = "start," + misc_name;
182     if (!Sendmsg(msg)) {
183         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
184         return false;
185     }
186 
187     std::string str = Receivemsg();
188     if (str != "success") {
189         LOG(ERROR) << "Failed to receive ack for " << msg << " from snapuserd daemon";
190         return false;
191     }
192 
193     LOG(DEBUG) << "Snapuserd daemon initialized with " << msg;
194     return true;
195 }
196 
InitDmUserCow(const std::string & misc_name,const std::string & cow_device,const std::string & backing_device,const std::string & base_path_merge)197 uint64_t SnapuserdClient::InitDmUserCow(const std::string& misc_name, const std::string& cow_device,
198                                         const std::string& backing_device,
199                                         const std::string& base_path_merge) {
200     std::vector<std::string> parts;
201 
202     if (base_path_merge.empty()) {
203         parts = {"init", misc_name, cow_device, backing_device};
204     } else {
205         // For userspace snapshots
206         parts = {"init", misc_name, cow_device, backing_device, base_path_merge};
207     }
208     std::string msg = android::base::Join(parts, ",");
209     if (!Sendmsg(msg)) {
210         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
211         return 0;
212     }
213 
214     std::string str = Receivemsg();
215 
216     std::vector<std::string> input = android::base::Split(str, ",");
217 
218     if (input.empty() || input[0] != "success") {
219         LOG(ERROR) << "Failed to receive number of sectors for " << msg << " from snapuserd daemon";
220         return 0;
221     }
222 
223     LOG(DEBUG) << "Snapuserd daemon COW device initialized: " << cow_device
224                << " Num-sectors: " << input[1];
225 
226     uint64_t num_sectors = 0;
227     if (!android::base::ParseUint(input[1], &num_sectors)) {
228         LOG(ERROR) << "Failed to parse input string to sectors";
229         return 0;
230     }
231     return num_sectors;
232 }
233 
DetachSnapuserd()234 bool SnapuserdClient::DetachSnapuserd() {
235     if (!Sendmsg("detach")) {
236         LOG(ERROR) << "Failed to detach snapuserd.";
237         return false;
238     }
239     return true;
240 }
241 
InitiateMerge(const std::string & misc_name)242 bool SnapuserdClient::InitiateMerge(const std::string& misc_name) {
243     std::string msg = "initiate_merge," + misc_name;
244     if (!Sendmsg(msg)) {
245         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
246         return false;
247     }
248     std::string response = Receivemsg();
249     return response == "success";
250 }
251 
GetMergePercent()252 double SnapuserdClient::GetMergePercent() {
253     std::string msg = "merge_percent";
254     if (!Sendmsg(msg)) {
255         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
256         return false;
257     }
258     std::string response = Receivemsg();
259 
260     return std::stod(response);
261 }
262 
QuerySnapshotStatus(const std::string & misc_name)263 std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) {
264     std::string msg = "getstatus," + misc_name;
265     if (!Sendmsg(msg)) {
266         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
267         return "snapshot-merge-failed";
268     }
269     return Receivemsg();
270 }
271 
QueryUpdateVerification()272 bool SnapuserdClient::QueryUpdateVerification() {
273     std::string msg = "update-verify";
274     if (!Sendmsg(msg)) {
275         LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
276         return false;
277     }
278     std::string response = Receivemsg();
279     return response == "success";
280 }
281 
282 }  // namespace snapshot
283 }  // namespace android
284