1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*e7c364b6SAndroid Build Coastguard Worker *
4*e7c364b6SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c364b6SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*e7c364b6SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*e7c364b6SAndroid Build Coastguard Worker *
8*e7c364b6SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*e7c364b6SAndroid Build Coastguard Worker *
10*e7c364b6SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*e7c364b6SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c364b6SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c364b6SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*e7c364b6SAndroid Build Coastguard Worker * limitations under the License.
15*e7c364b6SAndroid Build Coastguard Worker */
16*e7c364b6SAndroid Build Coastguard Worker
17*e7c364b6SAndroid Build Coastguard Worker #include <errno.h>
18*e7c364b6SAndroid Build Coastguard Worker #include <fcntl.h>
19*e7c364b6SAndroid Build Coastguard Worker #include <signal.h>
20*e7c364b6SAndroid Build Coastguard Worker #include <strings.h>
21*e7c364b6SAndroid Build Coastguard Worker #include <sys/mount.h>
22*e7c364b6SAndroid Build Coastguard Worker #include <sys/socket.h>
23*e7c364b6SAndroid Build Coastguard Worker #include <sys/stat.h>
24*e7c364b6SAndroid Build Coastguard Worker #include <sys/wait.h>
25*e7c364b6SAndroid Build Coastguard Worker #include <unistd.h>
26*e7c364b6SAndroid Build Coastguard Worker
27*e7c364b6SAndroid Build Coastguard Worker #include <string>
28*e7c364b6SAndroid Build Coastguard Worker #include <vector>
29*e7c364b6SAndroid Build Coastguard Worker
30*e7c364b6SAndroid Build Coastguard Worker #include <android-base/file.h>
31*e7c364b6SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
32*e7c364b6SAndroid Build Coastguard Worker #include <gtest/gtest.h>
33*e7c364b6SAndroid Build Coastguard Worker
34*e7c364b6SAndroid Build Coastguard Worker #include "adb.h"
35*e7c364b6SAndroid Build Coastguard Worker #include "adb_io.h"
36*e7c364b6SAndroid Build Coastguard Worker #include "fuse_adb_provider.h"
37*e7c364b6SAndroid Build Coastguard Worker #include "fuse_sideload.h"
38*e7c364b6SAndroid Build Coastguard Worker #include "minadbd/types.h"
39*e7c364b6SAndroid Build Coastguard Worker #include "minadbd_services.h"
40*e7c364b6SAndroid Build Coastguard Worker #include "socket.h"
41*e7c364b6SAndroid Build Coastguard Worker
42*e7c364b6SAndroid Build Coastguard Worker class MinadbdServicesTest : public ::testing::Test {
43*e7c364b6SAndroid Build Coastguard Worker protected:
44*e7c364b6SAndroid Build Coastguard Worker static constexpr int EXIT_TIME_OUT = 10;
45*e7c364b6SAndroid Build Coastguard Worker
SetUp()46*e7c364b6SAndroid Build Coastguard Worker void SetUp() override {
47*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(
48*e7c364b6SAndroid Build Coastguard Worker android::base::Socketpair(AF_UNIX, SOCK_STREAM, 0, &minadbd_socket_, &recovery_socket_));
49*e7c364b6SAndroid Build Coastguard Worker SetMinadbdSocketFd(minadbd_socket_);
50*e7c364b6SAndroid Build Coastguard Worker SetSideloadMountPoint(mount_point_.path);
51*e7c364b6SAndroid Build Coastguard Worker
52*e7c364b6SAndroid Build Coastguard Worker package_path_ = std::string(mount_point_.path) + "/" + FUSE_SIDELOAD_HOST_FILENAME;
53*e7c364b6SAndroid Build Coastguard Worker exit_flag_ = std::string(mount_point_.path) + "/" + FUSE_SIDELOAD_HOST_EXIT_FLAG;
54*e7c364b6SAndroid Build Coastguard Worker
55*e7c364b6SAndroid Build Coastguard Worker signal(SIGPIPE, SIG_IGN);
56*e7c364b6SAndroid Build Coastguard Worker }
57*e7c364b6SAndroid Build Coastguard Worker
TearDown()58*e7c364b6SAndroid Build Coastguard Worker void TearDown() override {
59*e7c364b6SAndroid Build Coastguard Worker // Umount in case the test fails. Ignore the result.
60*e7c364b6SAndroid Build Coastguard Worker umount(mount_point_.path);
61*e7c364b6SAndroid Build Coastguard Worker
62*e7c364b6SAndroid Build Coastguard Worker signal(SIGPIPE, SIG_DFL);
63*e7c364b6SAndroid Build Coastguard Worker }
64*e7c364b6SAndroid Build Coastguard Worker
ReadAndCheckCommandMessage(int fd,MinadbdCommand expected_command)65*e7c364b6SAndroid Build Coastguard Worker void ReadAndCheckCommandMessage(int fd, MinadbdCommand expected_command) {
66*e7c364b6SAndroid Build Coastguard Worker std::vector<uint8_t> received(kMinadbdMessageSize, '\0');
67*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFully(fd, received.data(), kMinadbdMessageSize));
68*e7c364b6SAndroid Build Coastguard Worker
69*e7c364b6SAndroid Build Coastguard Worker std::vector<uint8_t> expected(kMinadbdMessageSize, '\0');
70*e7c364b6SAndroid Build Coastguard Worker memcpy(expected.data(), kMinadbdCommandPrefix, strlen(kMinadbdCommandPrefix));
71*e7c364b6SAndroid Build Coastguard Worker memcpy(expected.data() + strlen(kMinadbdCommandPrefix), &expected_command,
72*e7c364b6SAndroid Build Coastguard Worker sizeof(expected_command));
73*e7c364b6SAndroid Build Coastguard Worker ASSERT_EQ(expected, received);
74*e7c364b6SAndroid Build Coastguard Worker }
75*e7c364b6SAndroid Build Coastguard Worker
WaitForFusePath()76*e7c364b6SAndroid Build Coastguard Worker void WaitForFusePath() {
77*e7c364b6SAndroid Build Coastguard Worker constexpr int TIME_OUT = 10;
78*e7c364b6SAndroid Build Coastguard Worker for (int i = 0; i < TIME_OUT; ++i) {
79*e7c364b6SAndroid Build Coastguard Worker struct stat sb;
80*e7c364b6SAndroid Build Coastguard Worker if (stat(package_path_.c_str(), &sb) == 0) {
81*e7c364b6SAndroid Build Coastguard Worker return;
82*e7c364b6SAndroid Build Coastguard Worker }
83*e7c364b6SAndroid Build Coastguard Worker
84*e7c364b6SAndroid Build Coastguard Worker if (errno == ENOENT) {
85*e7c364b6SAndroid Build Coastguard Worker sleep(1);
86*e7c364b6SAndroid Build Coastguard Worker continue;
87*e7c364b6SAndroid Build Coastguard Worker }
88*e7c364b6SAndroid Build Coastguard Worker FAIL() << "Timed out waiting for the fuse-provided package " << strerror(errno);
89*e7c364b6SAndroid Build Coastguard Worker }
90*e7c364b6SAndroid Build Coastguard Worker }
91*e7c364b6SAndroid Build Coastguard Worker
StatExitFlagAndExitProcess(int exit_code)92*e7c364b6SAndroid Build Coastguard Worker void StatExitFlagAndExitProcess(int exit_code) {
93*e7c364b6SAndroid Build Coastguard Worker struct stat sb;
94*e7c364b6SAndroid Build Coastguard Worker if (stat(exit_flag_.c_str(), &sb) != 0) {
95*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to stat " << exit_flag_;
96*e7c364b6SAndroid Build Coastguard Worker }
97*e7c364b6SAndroid Build Coastguard Worker
98*e7c364b6SAndroid Build Coastguard Worker exit(exit_code);
99*e7c364b6SAndroid Build Coastguard Worker }
100*e7c364b6SAndroid Build Coastguard Worker
WriteMinadbdCommandStatus(MinadbdCommandStatus status)101*e7c364b6SAndroid Build Coastguard Worker void WriteMinadbdCommandStatus(MinadbdCommandStatus status) {
102*e7c364b6SAndroid Build Coastguard Worker std::string status_message(kMinadbdMessageSize, '\0');
103*e7c364b6SAndroid Build Coastguard Worker memcpy(status_message.data(), kMinadbdStatusPrefix, strlen(kMinadbdStatusPrefix));
104*e7c364b6SAndroid Build Coastguard Worker memcpy(status_message.data() + strlen(kMinadbdStatusPrefix), &status, sizeof(status));
105*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(
106*e7c364b6SAndroid Build Coastguard Worker android::base::WriteFully(recovery_socket_, status_message.data(), kMinadbdMessageSize));
107*e7c364b6SAndroid Build Coastguard Worker }
108*e7c364b6SAndroid Build Coastguard Worker
ExecuteCommandAndWaitForExit(const std::string & command)109*e7c364b6SAndroid Build Coastguard Worker void ExecuteCommandAndWaitForExit(const std::string& command) {
110*e7c364b6SAndroid Build Coastguard Worker unique_fd fd = daemon_service_to_fd(command, nullptr);
111*e7c364b6SAndroid Build Coastguard Worker ASSERT_NE(-1, fd);
112*e7c364b6SAndroid Build Coastguard Worker sleep(EXIT_TIME_OUT);
113*e7c364b6SAndroid Build Coastguard Worker }
114*e7c364b6SAndroid Build Coastguard Worker
115*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd minadbd_socket_;
116*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd recovery_socket_;
117*e7c364b6SAndroid Build Coastguard Worker
118*e7c364b6SAndroid Build Coastguard Worker TemporaryDir mount_point_;
119*e7c364b6SAndroid Build Coastguard Worker std::string package_path_;
120*e7c364b6SAndroid Build Coastguard Worker std::string exit_flag_;
121*e7c364b6SAndroid Build Coastguard Worker };
122*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_wrong_size_argument)123*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_wrong_size_argument) {
124*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(ExecuteCommandAndWaitForExit("sideload-host:abc:4096"),
125*e7c364b6SAndroid Build Coastguard Worker ::testing::ExitedWithCode(kMinadbdHostCommandArgumentError), "");
126*e7c364b6SAndroid Build Coastguard Worker }
127*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_wrong_block_size)128*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_wrong_block_size) {
129*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(ExecuteCommandAndWaitForExit("sideload-host:10:20"),
130*e7c364b6SAndroid Build Coastguard Worker ::testing::ExitedWithCode(kMinadbdFuseStartError), "");
131*e7c364b6SAndroid Build Coastguard Worker }
132*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_broken_minadbd_socket)133*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_broken_minadbd_socket) {
134*e7c364b6SAndroid Build Coastguard Worker SetMinadbdSocketFd(-1);
135*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(ExecuteCommandAndWaitForExit("sideload-host:4096:4096"),
136*e7c364b6SAndroid Build Coastguard Worker ::testing::ExitedWithCode(kMinadbdSocketIOError), "");
137*e7c364b6SAndroid Build Coastguard Worker }
138*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_broken_recovery_socket)139*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_broken_recovery_socket) {
140*e7c364b6SAndroid Build Coastguard Worker recovery_socket_.reset();
141*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(ExecuteCommandAndWaitForExit("sideload-host:4096:4096"),
142*e7c364b6SAndroid Build Coastguard Worker ::testing::ExitedWithCode(kMinadbdSocketIOError), "");
143*e7c364b6SAndroid Build Coastguard Worker }
144*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_wrong_command_format)145*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_wrong_command_format) {
146*e7c364b6SAndroid Build Coastguard Worker auto test_body = [&](const std::string& command) {
147*e7c364b6SAndroid Build Coastguard Worker unique_fd fd = daemon_service_to_fd(command, nullptr);
148*e7c364b6SAndroid Build Coastguard Worker ASSERT_NE(-1, fd);
149*e7c364b6SAndroid Build Coastguard Worker WaitForFusePath();
150*e7c364b6SAndroid Build Coastguard Worker ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommand::kInstall);
151*e7c364b6SAndroid Build Coastguard Worker
152*e7c364b6SAndroid Build Coastguard Worker struct stat sb;
153*e7c364b6SAndroid Build Coastguard Worker ASSERT_EQ(0, stat(exit_flag_.c_str(), &sb));
154*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(android::base::WriteStringToFd("12345678", recovery_socket_));
155*e7c364b6SAndroid Build Coastguard Worker sleep(EXIT_TIME_OUT);
156*e7c364b6SAndroid Build Coastguard Worker };
157*e7c364b6SAndroid Build Coastguard Worker
158*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(test_body("sideload-host:4096:4096"),
159*e7c364b6SAndroid Build Coastguard Worker ::testing::ExitedWithCode(kMinadbdMessageFormatError), "");
160*e7c364b6SAndroid Build Coastguard Worker }
161*e7c364b6SAndroid Build Coastguard Worker
TEST_F(MinadbdServicesTest,SideloadHostService_read_data_from_fuse)162*e7c364b6SAndroid Build Coastguard Worker TEST_F(MinadbdServicesTest, SideloadHostService_read_data_from_fuse) {
163*e7c364b6SAndroid Build Coastguard Worker auto test_body = [&]() {
164*e7c364b6SAndroid Build Coastguard Worker std::vector<uint8_t> content(4096, 'a');
165*e7c364b6SAndroid Build Coastguard Worker // Start a new process instead of a thread to read from the package mounted by FUSE. Because
166*e7c364b6SAndroid Build Coastguard Worker // the test may not exit and report failures correctly when the thread blocks by a syscall.
167*e7c364b6SAndroid Build Coastguard Worker pid_t pid = fork();
168*e7c364b6SAndroid Build Coastguard Worker if (pid == 0) {
169*e7c364b6SAndroid Build Coastguard Worker WaitForFusePath();
170*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(package_path_.c_str(), O_RDONLY)));
171*e7c364b6SAndroid Build Coastguard Worker // Do not use assertion here because we want to stat the exit flag and exit the process.
172*e7c364b6SAndroid Build Coastguard Worker // Otherwise the test will wait for the time out instead of failing immediately.
173*e7c364b6SAndroid Build Coastguard Worker if (fd == -1) {
174*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to open " << package_path_;
175*e7c364b6SAndroid Build Coastguard Worker StatExitFlagAndExitProcess(1);
176*e7c364b6SAndroid Build Coastguard Worker }
177*e7c364b6SAndroid Build Coastguard Worker std::vector<uint8_t> content_from_fuse(4096);
178*e7c364b6SAndroid Build Coastguard Worker if (!android::base::ReadFully(fd, content_from_fuse.data(), 4096)) {
179*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to read from " << package_path_;
180*e7c364b6SAndroid Build Coastguard Worker StatExitFlagAndExitProcess(1);
181*e7c364b6SAndroid Build Coastguard Worker }
182*e7c364b6SAndroid Build Coastguard Worker if (content_from_fuse != content) {
183*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Content read from fuse doesn't match with the expected value";
184*e7c364b6SAndroid Build Coastguard Worker StatExitFlagAndExitProcess(1);
185*e7c364b6SAndroid Build Coastguard Worker }
186*e7c364b6SAndroid Build Coastguard Worker StatExitFlagAndExitProcess(0);
187*e7c364b6SAndroid Build Coastguard Worker }
188*e7c364b6SAndroid Build Coastguard Worker
189*e7c364b6SAndroid Build Coastguard Worker unique_fd fd = daemon_service_to_fd("sideload-host:4096:4096", nullptr);
190*e7c364b6SAndroid Build Coastguard Worker ASSERT_NE(-1, fd);
191*e7c364b6SAndroid Build Coastguard Worker ReadAndCheckCommandMessage(recovery_socket_, MinadbdCommand::kInstall);
192*e7c364b6SAndroid Build Coastguard Worker
193*e7c364b6SAndroid Build Coastguard Worker // Mimic the response from adb host.
194*e7c364b6SAndroid Build Coastguard Worker std::string adb_message(8, '\0');
195*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(android::base::ReadFully(fd, adb_message.data(), 8));
196*e7c364b6SAndroid Build Coastguard Worker ASSERT_EQ(android::base::StringPrintf("%08u", 0), adb_message);
197*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(android::base::WriteFully(fd, content.data(), 4096));
198*e7c364b6SAndroid Build Coastguard Worker
199*e7c364b6SAndroid Build Coastguard Worker // Check that we read the correct data from fuse.
200*e7c364b6SAndroid Build Coastguard Worker int child_status;
201*e7c364b6SAndroid Build Coastguard Worker waitpid(pid, &child_status, 0);
202*e7c364b6SAndroid Build Coastguard Worker ASSERT_TRUE(WIFEXITED(child_status));
203*e7c364b6SAndroid Build Coastguard Worker ASSERT_EQ(0, WEXITSTATUS(child_status));
204*e7c364b6SAndroid Build Coastguard Worker
205*e7c364b6SAndroid Build Coastguard Worker WriteMinadbdCommandStatus(MinadbdCommandStatus::kSuccess);
206*e7c364b6SAndroid Build Coastguard Worker
207*e7c364b6SAndroid Build Coastguard Worker // TODO(xunchang) check if adb host-side receives "DONEDONE", there's a race condition between
208*e7c364b6SAndroid Build Coastguard Worker // receiving the message and exit of test body (by detached thread in minadbd service).
209*e7c364b6SAndroid Build Coastguard Worker exit(kMinadbdSuccess);
210*e7c364b6SAndroid Build Coastguard Worker };
211*e7c364b6SAndroid Build Coastguard Worker
212*e7c364b6SAndroid Build Coastguard Worker ASSERT_EXIT(test_body(), ::testing::ExitedWithCode(kMinadbdSuccess), "");
213*e7c364b6SAndroid Build Coastguard Worker }
214