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 #define LOG_TAG "dumpstate_1_1_hidl_hal_test"
18 
19 #include <fcntl.h>
20 #include <unistd.h>
21 
22 #include <functional>
23 #include <tuple>
24 #include <vector>
25 
26 #include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
27 #include <android/hardware/dumpstate/1.1/types.h>
28 #include <cutils/native_handle.h>
29 #include <gtest/gtest.h>
30 #include <hidl/GtestPrinter.h>
31 #include <hidl/HidlSupport.h>
32 #include <hidl/ServiceManagement.h>
33 #include <log/log.h>
34 
35 namespace {
36 
37 using ::android::sp;
38 using ::android::hardware::Return;
39 using ::android::hardware::dumpstate::V1_1::DumpstateMode;
40 using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
41 using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
42 using ::android::hardware::dumpstate::V1_1::toString;
43 
44 // Base class common to all dumpstate HAL v1.1 tests.
45 template <typename T>
46 class DumpstateHidl1_1TestBase : public ::testing::TestWithParam<T> {
47   protected:
SetUp()48     virtual void SetUp() override { GetService(); }
49 
50     virtual std::string GetInstanceName() = 0;
51 
GetService()52     void GetService() {
53         const std::string instance_name = GetInstanceName();
54         dumpstate = IDumpstateDevice::getService(instance_name);
55         ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance " << instance_name;
56     }
57 
ToggleVerboseLogging(bool enable)58     void ToggleVerboseLogging(bool enable) {
59         Return<void> status = dumpstate->setVerboseLoggingEnabled(enable);
60         ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
61 
62         if (!dumpstate->ping().isOk()) {
63             ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get "
64                   "again");
65             GetService();
66         }
67 
68         Return<bool> logging_enabled = dumpstate->getVerboseLoggingEnabled();
69         ASSERT_TRUE(logging_enabled.isOk())
70                 << "Status should be ok: " << logging_enabled.description();
71         ASSERT_EQ(logging_enabled, enable)
72                 << "Verbose logging should now be " << (enable ? "enabled" : "disabled");
73 
74         if (!dumpstate->ping().isOk()) {
75             ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get "
76                   "again");
77             GetService();
78         }
79     }
80 
EnableVerboseLogging()81     void EnableVerboseLogging() { ToggleVerboseLogging(true); }
82 
DisableVerboseLogging()83     void DisableVerboseLogging() { ToggleVerboseLogging(false); }
84 
85     sp<IDumpstateDevice> dumpstate;
86 };
87 
88 // Tests that don't need to iterate every single DumpstateMode value for dumpstateBoard_1_1.
89 class DumpstateHidl1_1GeneralTest : public DumpstateHidl1_1TestBase<std::string> {
90   protected:
GetInstanceName()91     virtual std::string GetInstanceName() override { return GetParam(); }
92 };
93 
94 // Tests that iterate every single DumpstateMode value for dumpstateBoard_1_1.
95 class DumpstateHidl1_1PerModeTest
96     : public DumpstateHidl1_1TestBase<std::tuple<std::string, DumpstateMode>> {
97   protected:
GetInstanceName()98     virtual std::string GetInstanceName() override { return std::get<0>(GetParam()); }
99 
GetMode()100     DumpstateMode GetMode() { return std::get<1>(GetParam()); }
101 
102     // Will only execute additional_assertions when status == expected.
AssertStatusForMode(const Return<DumpstateStatus> & status,const DumpstateStatus expected,std::function<void ()> additional_assertions=nullptr)103     void AssertStatusForMode(const Return<DumpstateStatus>& status, const DumpstateStatus expected,
104                              std::function<void()> additional_assertions = nullptr) {
105         ASSERT_TRUE(status.isOk())
106                 << "Status should be ok and return a more specific DumpstateStatus: "
107                 << status.description();
108         if (GetMode() == DumpstateMode::DEFAULT) {
109             ASSERT_EQ(expected, status)
110                     << "Required mode (DumpstateMode::" << toString(GetMode())
111                     << "): status should be DumpstateStatus::" << toString(expected)
112                     << ", but got DumpstateStatus::" << toString(status);
113         } else {
114             // The rest of the modes are optional to support, but they MUST return either the
115             // expected value or UNSUPPORTED_MODE.
116             ASSERT_TRUE(status == expected || status == DumpstateStatus::UNSUPPORTED_MODE)
117                     << "Optional mode (DumpstateMode::" << toString(GetMode())
118                     << "): status should be DumpstateStatus::" << toString(expected)
119                     << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::"
120                     << toString(status);
121         }
122         if (status == expected && additional_assertions != nullptr) {
123             additional_assertions();
124         }
125     }
126 };
127 
128 constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000;  // 30 seconds
129 
130 // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
TEST_P(DumpstateHidl1_1PerModeTest,TestNullHandle)131 TEST_P(DumpstateHidl1_1PerModeTest, TestNullHandle) {
132     EnableVerboseLogging();
133 
134     Return<DumpstateStatus> status =
135             dumpstate->dumpstateBoard_1_1(nullptr, GetMode(), kDefaultTimeoutMillis);
136 
137     AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
138 }
139 
140 // Negative test: make sure dumpstateBoard() ignores a handle with no FD.
TEST_P(DumpstateHidl1_1PerModeTest,TestHandleWithNoFd)141 TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithNoFd) {
142     EnableVerboseLogging();
143 
144     native_handle_t* handle = native_handle_create(0, 0);
145     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
146 
147     Return<DumpstateStatus> status =
148             dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
149 
150     AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
151 
152     native_handle_close(handle);
153     native_handle_delete(handle);
154 }
155 
156 // Positive test: make sure dumpstateBoard() writes something to the FD.
TEST_P(DumpstateHidl1_1PerModeTest,TestOk)157 TEST_P(DumpstateHidl1_1PerModeTest, TestOk) {
158     EnableVerboseLogging();
159 
160     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
161     int fds[2];
162     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
163 
164     native_handle_t* handle = native_handle_create(1, 0);
165     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
166     handle->data[0] = fds[1];
167 
168     Return<DumpstateStatus> status =
169             dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
170 
171     AssertStatusForMode(status, DumpstateStatus::OK, [&fds]() {
172         // Check that at least one byte was written.
173         char buff;
174         ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
175     });
176 
177     native_handle_close(handle);
178     native_handle_delete(handle);
179 }
180 
181 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
TEST_P(DumpstateHidl1_1PerModeTest,TestHandleWithTwoFds)182 TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithTwoFds) {
183     EnableVerboseLogging();
184 
185     int fds1[2];
186     int fds2[2];
187     ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
188     ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno;
189 
190     native_handle_t* handle = native_handle_create(2, 0);
191     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
192     handle->data[0] = fds1[1];
193     handle->data[1] = fds2[1];
194 
195     Return<DumpstateStatus> status =
196             dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
197 
198     AssertStatusForMode(status, DumpstateStatus::OK, [&fds1, &fds2]() {
199         // Check that at least one byte was written to one of the FDs.
200         char buff;
201         size_t read1 = read(fds1[0], &buff, 1);
202         size_t read2 = read(fds2[0], &buff, 1);
203         // Sometimes read returns -1, so we can't just add them together and expect >= 1.
204         ASSERT_TRUE(read1 == 1 || read2 == 1) << "Dumped nothing";
205     });
206 
207     native_handle_close(handle);
208     native_handle_delete(handle);
209 }
210 
211 // Make sure dumpstateBoard_1_1 actually validates its arguments.
TEST_P(DumpstateHidl1_1GeneralTest,TestInvalidModeArgument_Negative)212 TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Negative) {
213     EnableVerboseLogging();
214 
215     int fds[2];
216     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
217 
218     native_handle_t* handle = native_handle_create(1, 0);
219     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
220     handle->data[0] = fds[1];
221 
222     Return<DumpstateStatus> status = dumpstate->dumpstateBoard_1_1(
223             handle, static_cast<DumpstateMode>(-100), kDefaultTimeoutMillis);
224 
225     ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
226                                << status.description();
227     ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT)
228             << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param";
229 
230     native_handle_close(handle);
231     native_handle_delete(handle);
232 }
233 
TEST_P(DumpstateHidl1_1GeneralTest,TestInvalidModeArgument_Undefined)234 TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Undefined) {
235     EnableVerboseLogging();
236 
237     int fds[2];
238     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
239 
240     native_handle_t* handle = native_handle_create(1, 0);
241     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
242     handle->data[0] = fds[1];
243 
244     Return<DumpstateStatus> status = dumpstate->dumpstateBoard_1_1(
245             handle, static_cast<DumpstateMode>(9001), kDefaultTimeoutMillis);
246 
247     ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
248                                << status.description();
249     ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT)
250             << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param";
251 
252     native_handle_close(handle);
253     native_handle_delete(handle);
254 }
255 
256 // Positive test: make sure dumpstateBoard() from 1.0 doesn't fail.
TEST_P(DumpstateHidl1_1GeneralTest,Test1_0MethodOk)257 TEST_P(DumpstateHidl1_1GeneralTest, Test1_0MethodOk) {
258     EnableVerboseLogging();
259 
260     int fds[2];
261     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
262 
263     native_handle_t* handle = native_handle_create(1, 0);
264     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
265     handle->data[0] = fds[1];
266 
267     Return<void> status = dumpstate->dumpstateBoard(handle);
268 
269     ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
270 
271     // Check that at least one byte was written.
272     char buff;
273     ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
274 
275     native_handle_close(handle);
276     native_handle_delete(handle);
277 }
278 
279 // Make sure disabling verbose logging behaves correctly. Some info is still allowed to be emitted,
280 // but it can't have privacy/storage/battery impacts.
TEST_P(DumpstateHidl1_1PerModeTest,TestDeviceLoggingDisabled)281 TEST_P(DumpstateHidl1_1PerModeTest, TestDeviceLoggingDisabled) {
282     DisableVerboseLogging();
283 
284     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
285     int fds[2];
286     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
287 
288     native_handle_t* handle = native_handle_create(1, 0);
289     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
290     handle->data[0] = fds[1];
291 
292     Return<DumpstateStatus> status =
293             dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
294 
295     // We don't include additional assertions here about the file passed in. If verbose logging is
296     // disabled, the OEM may choose to include nothing at all, but it is allowed to include some
297     // essential information based on the mode as long as it isn't private user information.
298     AssertStatusForMode(status, DumpstateStatus::OK);
299 
300     native_handle_close(handle);
301     native_handle_delete(handle);
302 }
303 
304 // Double-enable is perfectly valid, but the second call shouldn't do anything.
TEST_P(DumpstateHidl1_1GeneralTest,TestRepeatedEnable)305 TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedEnable) {
306     EnableVerboseLogging();
307     EnableVerboseLogging();
308 }
309 
310 // Double-disable is perfectly valid, but the second call shouldn't do anything.
TEST_P(DumpstateHidl1_1GeneralTest,TestRepeatedDisable)311 TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedDisable) {
312     DisableVerboseLogging();
313     DisableVerboseLogging();
314 }
315 
316 // Toggling in short order is perfectly valid.
TEST_P(DumpstateHidl1_1GeneralTest,TestRepeatedToggle)317 TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedToggle) {
318     EnableVerboseLogging();
319     DisableVerboseLogging();
320     EnableVerboseLogging();
321     DisableVerboseLogging();
322 }
323 
324 INSTANTIATE_TEST_SUITE_P(
325         PerInstance, DumpstateHidl1_1GeneralTest,
326         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
327         android::hardware::PrintInstanceNameToString);
328 
329 // Includes the mode's name as part of the description string.
PrintInstanceNameToStringWithMode(const testing::TestParamInfo<std::tuple<std::string,DumpstateMode>> & info)330 static inline std::string PrintInstanceNameToStringWithMode(
331         const testing::TestParamInfo<std::tuple<std::string, DumpstateMode>>& info) {
332     return android::hardware::PrintInstanceNameToString(
333                    testing::TestParamInfo(std::get<0>(info.param), info.index)) +
334            "_" + toString(std::get<1>(info.param));
335 }
336 
337 INSTANTIATE_TEST_SUITE_P(
338         PerInstanceAndMode, DumpstateHidl1_1PerModeTest,
339         testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
340                                  IDumpstateDevice::descriptor)),
341                          testing::ValuesIn(android::hardware::hidl_enum_range<DumpstateMode>())),
342         PrintInstanceNameToStringWithMode);
343 
344 }  // namespace
345