1 /*
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 <string>
18 #include <vector>
19 
20 #include <android-base/strings.h>
21 #include <bootloader_message/bootloader_message.h>
22 #include <gtest/gtest.h>
23 
24 #include "common/component_test_util.h"
25 
26 class BootloaderMessageTest : public ::testing::Test {
27  protected:
BootloaderMessageTest()28   BootloaderMessageTest() : has_misc(true) {}
29 
SetUp()30   virtual void SetUp() override {
31     has_misc = parse_misc();
32   }
33 
TearDown()34   virtual void TearDown() override {
35     // Clear the BCB.
36     if (has_misc) {
37       std::string err;
38       ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
39     }
40   }
41 
42   bool has_misc;
43 };
44 
TEST_F(BootloaderMessageTest,clear_bootloader_message)45 TEST_F(BootloaderMessageTest, clear_bootloader_message) {
46   if (!has_misc) {
47     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
48     return;
49   }
50 
51   // Clear the BCB.
52   std::string err;
53   ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
54 
55   // Verify the content.
56   bootloader_message boot;
57   ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
58 
59   // All the bytes should be cleared.
60   ASSERT_EQ(std::string(sizeof(boot), '\0'),
61             std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
62 }
63 
TEST_F(BootloaderMessageTest,read_and_write_bootloader_message)64 TEST_F(BootloaderMessageTest, read_and_write_bootloader_message) {
65   if (!has_misc) {
66     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
67     return;
68   }
69 
70   // Write the BCB.
71   bootloader_message boot = {};
72   strlcpy(boot.command, "command", sizeof(boot.command));
73   strlcpy(boot.recovery, "message1\nmessage2\n", sizeof(boot.recovery));
74   strlcpy(boot.status, "status1", sizeof(boot.status));
75 
76   std::string err;
77   ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err;
78 
79   // Read and verify.
80   bootloader_message boot_verify;
81   ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err;
82 
83   ASSERT_EQ(std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)),
84             std::string(reinterpret_cast<const char*>(&boot_verify), sizeof(boot_verify)));
85 }
86 
TEST_F(BootloaderMessageTest,write_bootloader_message_options)87 TEST_F(BootloaderMessageTest, write_bootloader_message_options) {
88   if (!has_misc) {
89     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
90     return;
91   }
92 
93   // Write the options to BCB.
94   std::vector<std::string> options = { "option1", "option2" };
95   std::string err;
96   ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
97 
98   // Inject some bytes into boot, which should be overwritten while reading.
99   bootloader_message boot;
100   strlcpy(boot.recovery, "random message", sizeof(boot.recovery));
101   strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved));
102 
103   ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
104 
105   // Verify that command and recovery fields should be set.
106   ASSERT_EQ("boot-recovery", std::string(boot.command));
107   std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
108   ASSERT_EQ(expected, std::string(boot.recovery));
109 
110   // The rest should be cleared.
111   ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
112   ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
113   ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
114             std::string(boot.reserved, sizeof(boot.reserved)));
115 }
116 
TEST_F(BootloaderMessageTest,write_bootloader_message_options_empty)117 TEST_F(BootloaderMessageTest, write_bootloader_message_options_empty) {
118   if (!has_misc) {
119     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
120     return;
121   }
122 
123   // Write empty vector.
124   std::vector<std::string> options;
125   std::string err;
126   ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
127 
128   // Read and verify.
129   bootloader_message boot;
130   ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
131 
132   // command and recovery fields should be set.
133   ASSERT_EQ("boot-recovery", std::string(boot.command));
134   ASSERT_EQ("recovery\n", std::string(boot.recovery));
135 
136   // The rest should be cleared.
137   ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
138   ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
139   ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
140             std::string(boot.reserved, sizeof(boot.reserved)));
141 }
142 
TEST_F(BootloaderMessageTest,write_bootloader_message_options_long)143 TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) {
144   if (!has_misc) {
145     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
146     return;
147   }
148 
149   // Write super long message.
150   std::vector<std::string> options;
151   for (int i = 0; i < 100; i++) {
152     options.push_back("option: " + std::to_string(i));
153   }
154 
155   std::string err;
156   ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
157 
158   // Read and verify.
159   bootloader_message boot;
160   ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
161 
162   // Make sure it's long enough.
163   std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
164   ASSERT_GE(expected.size(), sizeof(boot.recovery));
165 
166   // command and recovery fields should be set.
167   ASSERT_EQ("boot-recovery", std::string(boot.command));
168   ASSERT_EQ(expected.substr(0, sizeof(boot.recovery) - 1), std::string(boot.recovery));
169   ASSERT_EQ('\0', boot.recovery[sizeof(boot.recovery) - 1]);
170 
171   // The rest should be cleared.
172   ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
173   ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
174   ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
175             std::string(boot.reserved, sizeof(boot.reserved)));
176 }
177 
TEST_F(BootloaderMessageTest,update_bootloader_message)178 TEST_F(BootloaderMessageTest, update_bootloader_message) {
179   if (!has_misc) {
180     GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
181     return;
182   }
183 
184   // Inject some bytes into boot, which should be not overwritten later.
185   bootloader_message boot;
186   strlcpy(boot.recovery, "random message", sizeof(boot.recovery));
187   strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved));
188   std::string err;
189   ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err;
190 
191   // Update the BCB message.
192   std::vector<std::string> options = { "option1", "option2" };
193   ASSERT_TRUE(update_bootloader_message(options, &err)) << "Failed to update BCB: " << err;
194 
195   bootloader_message boot_verify;
196   ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err;
197 
198   // Verify that command and recovery fields should be set.
199   ASSERT_EQ("boot-recovery", std::string(boot_verify.command));
200   std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
201   ASSERT_EQ(expected, std::string(boot_verify.recovery));
202 
203   // The rest should be intact.
204   ASSERT_EQ(std::string(boot.status), std::string(boot_verify.status));
205   ASSERT_EQ(std::string(boot.stage), std::string(boot_verify.stage));
206   ASSERT_EQ(std::string(boot.reserved), std::string(boot_verify.reserved));
207 }
208