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