blob: a554c3e480f3a6853b4365d28199ceaa7807c42c [file] [log] [blame]
Tao Bao10334082016-12-12 17:10:20 -08001/*
2 * Copyright (C) 2016 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 <sys/socket.h>
19#include <sys/types.h>
20#include <sys/un.h>
21#include <unistd.h>
22
23#include <string>
24
25#include <android-base/file.h>
26#include <android-base/logging.h>
27#include <android-base/properties.h>
28#include <android-base/unique_fd.h>
29#include <bootloader_message/bootloader_message.h>
30#include <gtest/gtest.h>
31
32static const std::string UNCRYPT_SOCKET = "/dev/socket/uncrypt";
33static const std::string INIT_SVC_SETUP_BCB = "init.svc.setup-bcb";
34static const std::string INIT_SVC_CLEAR_BCB = "init.svc.clear-bcb";
35static const std::string INIT_SVC_UNCRYPT = "init.svc.uncrypt";
36static constexpr int SOCKET_CONNECTION_MAX_RETRY = 30;
37
38class UncryptTest : public ::testing::Test {
39 protected:
40 virtual void SetUp() {
41 ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb"));
42 ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb"));
43 ASSERT_TRUE(android::base::SetProperty("ctl.stop", "uncrypt"));
44
45 bool success = false;
46 for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
47 std::string setup_bcb = android::base::GetProperty(INIT_SVC_SETUP_BCB, "");
48 std::string clear_bcb = android::base::GetProperty(INIT_SVC_CLEAR_BCB, "");
49 std::string uncrypt = android::base::GetProperty(INIT_SVC_UNCRYPT, "");
50 LOG(INFO) << "setup-bcb: [" << setup_bcb << "] clear-bcb: [" << clear_bcb << "] uncrypt: ["
51 << uncrypt << "]";
52 if (setup_bcb != "running" && clear_bcb != "running" && uncrypt != "running") {
53 success = true;
54 break;
55 }
56 sleep(1);
57 }
58
59 ASSERT_TRUE(success) << "uncrypt service is not available.";
60 }
61};
62
63TEST_F(UncryptTest, setup_bcb) {
64 // Trigger the setup-bcb service.
65 ASSERT_TRUE(android::base::SetProperty("ctl.start", "setup-bcb"));
66
67 // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
68 sleep(1);
69
70 struct sockaddr_un un = {};
71 un.sun_family = AF_UNIX;
72 strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path));
73
74 int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
75 ASSERT_NE(-1, sockfd);
76
77 // Connect to the uncrypt socket.
78 bool success = false;
79 for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
80 if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&un), sizeof(struct sockaddr_un)) != 0) {
81 success = true;
82 break;
83 }
84 sleep(1);
85 }
86 ASSERT_TRUE(success);
87
88 // Send out the BCB message.
89 std::string message = "--update_message=abc value";
90 std::string message_in_bcb = "recovery\n--update_message=abc value\n";
91 int length = static_cast<int>(message.size());
92 int length_out = htonl(length);
93 ASSERT_TRUE(android::base::WriteFully(sockfd, &length_out, sizeof(int)))
94 << "Failed to write length: " << strerror(errno);
95 ASSERT_TRUE(android::base::WriteFully(sockfd, message.data(), length))
96 << "Failed to write message: " << strerror(errno);
97
98 // Check the status code from uncrypt.
99 int status;
100 ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int)));
101 ASSERT_EQ(100U, ntohl(status));
102
103 // Ack having received the status code.
104 int code = 0;
105 ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int)));
106
107 ASSERT_EQ(0, close(sockfd));
108
109 ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb"));
110
111 // Verify the message by reading from BCB directly.
112 bootloader_message boot;
113 std::string err;
114 ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
115
116 ASSERT_EQ("boot-recovery", std::string(boot.command));
117 ASSERT_EQ(message_in_bcb, std::string(boot.recovery));
118
119 // The rest of the boot.recovery message should be zero'd out.
120 ASSERT_LE(message_in_bcb.size(), sizeof(boot.recovery));
121 size_t left = sizeof(boot.recovery) - message_in_bcb.size();
122 ASSERT_EQ(std::string(left, '\0'), std::string(&boot.recovery[message_in_bcb.size()], left));
123
124 // Clear the BCB.
125 ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
126}
127
128TEST_F(UncryptTest, clear_bcb) {
129 // Trigger the clear-bcb service.
130 ASSERT_TRUE(android::base::SetProperty("ctl.start", "clear-bcb"));
131
132 // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
133 sleep(1);
134
135 struct sockaddr_un un = {};
136 un.sun_family = AF_UNIX;
137 strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path));
138
139 int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
140 ASSERT_NE(-1, sockfd);
141
142 // Connect to the uncrypt socket.
143 bool success = false;
144 for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
145 if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&un), sizeof(struct sockaddr_un)) != 0) {
146 success = true;
147 break;
148 }
149 sleep(1);
150 }
151 ASSERT_TRUE(success);
152
153 // Check the status code from uncrypt.
154 int status;
155 ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int)));
156 ASSERT_EQ(100U, ntohl(status));
157
158 // Ack having received the status code.
159 int code = 0;
160 ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int)));
161
162 ASSERT_EQ(0, close(sockfd));
163
164 ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb"));
165
166 // Verify the content by reading from BCB directly.
167 bootloader_message boot;
168 std::string err;
169 ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
170
171 // All the bytes should be cleared.
172 ASSERT_EQ(std::string(sizeof(boot), '\0'),
173 std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
174}