blob: 6f08f74690470bd45e7674d9214e5f6e63b4e9a9 [file] [log] [blame]
Yifan Hong9881df92017-05-10 14:33:05 -07001/*
2 * Copyright (C) 2017 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 "Lshal"
18#include <android-base/logging.h>
19
20#include <sstream>
21#include <string>
22#include <thread>
23#include <vector>
24
25#include <gtest/gtest.h>
26#include <gmock/gmock.h>
Yifan Hong5cceea82020-07-09 19:34:58 -070027#include <android/hardware/tests/inheritance/1.0/IChild.h>
Yifan Hong9881df92017-05-10 14:33:05 -070028#include <hidl/HidlTransportSupport.h>
Yifan Hong8bf73162017-09-07 18:06:13 -070029#include <vintf/parse_xml.h>
Yifan Hong9881df92017-05-10 14:33:05 -070030
Yifan Hongb2a2ecb2017-09-07 15:08:22 -070031#include "ListCommand.h"
Yifan Hong9881df92017-05-10 14:33:05 -070032#include "Lshal.h"
33
34#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
35
36using namespace testing;
37
Yifan Hong8bf73162017-09-07 18:06:13 -070038using ::android::hidl::base::V1_0::DebugInfo;
Yifan Hong9881df92017-05-10 14:33:05 -070039using ::android::hidl::base::V1_0::IBase;
40using ::android::hidl::manager::V1_0::IServiceManager;
41using ::android::hidl::manager::V1_0::IServiceNotification;
Yifan Hongfee209d2017-09-14 18:23:38 -070042using ::android::hardware::hidl_array;
Yifan Hong9881df92017-05-10 14:33:05 -070043using ::android::hardware::hidl_death_recipient;
44using ::android::hardware::hidl_handle;
45using ::android::hardware::hidl_string;
46using ::android::hardware::hidl_vec;
Yifan Hong5cceea82020-07-09 19:34:58 -070047using ::android::hardware::Void;
Yifan Hong0ad64f52018-05-25 15:29:17 -070048using android::vintf::Arch;
Yifan Hongbdf44f82018-05-25 14:20:00 -070049using android::vintf::CompatibilityMatrix;
Yifan Hongbdf44f82018-05-25 14:20:00 -070050using android::vintf::HalManifest;
Yifan Hong8304e412018-05-25 15:05:36 -070051using android::vintf::Transport;
Yifan Hongbdf44f82018-05-25 14:20:00 -070052using android::vintf::VintfObject;
Yifan Hong9881df92017-05-10 14:33:05 -070053
Yifan Hong8bf73162017-09-07 18:06:13 -070054using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
55
Yifan Hongfee209d2017-09-14 18:23:38 -070056using hidl_hash = hidl_array<uint8_t, 32>;
57
Yifan Hong9881df92017-05-10 14:33:05 -070058namespace android {
59namespace hardware {
60namespace tests {
Yifan Hong5cceea82020-07-09 19:34:58 -070061namespace inheritance {
Yifan Hong9881df92017-05-10 14:33:05 -070062namespace V1_0 {
63namespace implementation {
Yifan Hong5cceea82020-07-09 19:34:58 -070064struct Child : android::hardware::tests::inheritance::V1_0::IChild {
65 ::android::hardware::Return<void> doChild() override { return Void(); }
66 ::android::hardware::Return<void> doParent() override { return Void(); }
67 ::android::hardware::Return<void> doGrandparent() override { return Void(); }
68
Yifan Hong9881df92017-05-10 14:33:05 -070069 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
70 const native_handle_t *handle = hh.getNativeHandle();
71 if (handle->numFds < 1) {
72 return Void();
73 }
74 int fd = handle->data[0];
75 std::string content{descriptor};
76 for (const auto &option : options) {
77 content += "\n";
78 content += option.c_str();
79 }
80 ssize_t written = write(fd, content.c_str(), content.size());
81 if (written != (ssize_t)content.size()) {
Yifan Hong5cceea82020-07-09 19:34:58 -070082 LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
Yifan Hong9881df92017-05-10 14:33:05 -070083 << content.size() << " bytes, errno = " << errno;
84 }
85 return Void();
86 }
87};
88
89} // namespace implementation
90} // namespace V1_0
Yifan Hong5cceea82020-07-09 19:34:58 -070091} // namespace inheritance
Yifan Hong9881df92017-05-10 14:33:05 -070092} // namespace tests
93} // namespace hardware
94
95namespace lshal {
96
Yifan Hong9881df92017-05-10 14:33:05 -070097class MockServiceManager : public IServiceManager {
98public:
99 template<typename T>
100 using R = ::android::hardware::Return<T>;
101 using String = const hidl_string&;
102 ~MockServiceManager() = default;
103
104#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
105
106 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
107 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
108 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
109 MOCK_METHOD_CB(list);
110 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
111 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
112 MOCK_METHOD_CB(debugDump);
113 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
114 MOCK_METHOD_CB(interfaceChain);
115 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
116 MOCK_METHOD_CB(interfaceDescriptor);
117 MOCK_METHOD_CB(getHashChain);
118 MOCK_METHOD0(setHalInstrumentation, R<void>());
119 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
120 MOCK_METHOD0(ping, R<void>());
121 MOCK_METHOD_CB(getDebugInfo);
122 MOCK_METHOD0(notifySyspropsChanged, R<void>());
123 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
124
125};
126
Yifan Hongbf20a262017-09-07 11:10:58 -0700127class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700128public:
129 void SetUp() override {
Yifan Hong5cceea82020-07-09 19:34:58 -0700130 using ::android::hardware::tests::inheritance::V1_0::IChild;
131 using ::android::hardware::tests::inheritance::V1_0::IParent;
132 using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
133 using ::android::hardware::tests::inheritance::V1_0::implementation::Child;
Yifan Hong9881df92017-05-10 14:33:05 -0700134
135 err.str("");
136 out.str("");
137 serviceManager = new testing::NiceMock<MockServiceManager>();
Yifan Hong5cceea82020-07-09 19:34:58 -0700138 ON_CALL(*serviceManager, get(_, _))
139 .WillByDefault(
140 Invoke([](const auto& iface,
141 const auto& inst) -> ::android::hardware::Return<sp<IBase>> {
142 if (inst != "default") return nullptr;
143 if (iface == IChild::descriptor || iface == IParent::descriptor ||
144 iface == IGrandparent::descriptor)
145 return new Child();
146 return nullptr;
147 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700148
149 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700150 }
151 void TearDown() override {}
152
153 std::stringstream err;
154 std::stringstream out;
155 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700156
157 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700158};
159
Yifan Hongbf20a262017-09-07 11:10:58 -0700160static Arg createArg(const std::vector<const char*>& args) {
161 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
162}
163
164template<typename T>
165static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
166 return lshal->main(createArg(args));
167}
168
169TEST_F(DebugTest, Debug) {
170 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700171 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700172 }));
Yifan Hong5cceea82020-07-09 19:34:58 -0700173 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nfoo\nbar"));
Yifan Hong9881df92017-05-10 14:33:05 -0700174 EXPECT_THAT(err.str(), IsEmpty());
175}
176
Yifan Hongbf20a262017-09-07 11:10:58 -0700177TEST_F(DebugTest, Debug2) {
178 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700179 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700180 }));
Yifan Hong5cceea82020-07-09 19:34:58 -0700181 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nbaz\nquux"));
Yifan Hong9881df92017-05-10 14:33:05 -0700182 EXPECT_THAT(err.str(), IsEmpty());
183}
184
Yifan Hongbf20a262017-09-07 11:10:58 -0700185TEST_F(DebugTest, Debug3) {
186 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700187 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700188 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700189 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
190}
191
Yifan Hong5cceea82020-07-09 19:34:58 -0700192TEST_F(DebugTest, DebugParent) {
193 EXPECT_EQ(0u, callMain(lshal, {
194 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
195 }));
196 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\ncalling parent"));
197 EXPECT_THAT(err.str(), IsEmpty());
198}
199
200TEST_F(DebugTest, DebugParentExclude) {
201 EXPECT_EQ(0u, callMain(lshal, {
202 "lshal", "debug", "-E", "android.hardware.tests.inheritance@1.0::IParent", "excluding"
203 }));
204 EXPECT_THAT(out.str(), IsEmpty());
205 EXPECT_THAT(err.str(), IsEmpty());
206}
207
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700208class MockLshal : public Lshal {
209public:
210 MockLshal() {}
211 ~MockLshal() = default;
212 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
213 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
214};
215
216// expose protected fields and methods for ListCommand
217class MockListCommand : public ListCommand {
218public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800219 explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700220
Yifan Honga8bedc62017-09-08 18:00:31 -0700221 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
222 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700223 void forEachTable(const std::function<void(Table &)> &f) {
224 return ListCommand::forEachTable(f);
225 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700226 void forEachTable(const std::function<void(const Table &)> &f) const {
227 return ListCommand::forEachTable(f);
228 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700229 Status fetch() { return ListCommand::fetch(); }
230 void dumpVintf(const NullableOStream<std::ostream>& out) {
231 return ListCommand::dumpVintf(out);
232 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700233 void internalPostprocess() { ListCommand::postprocess(); }
Devin Moorec03e3aa2020-12-11 15:11:17 -0800234 const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
Yifan Hong1243dde2017-09-14 17:49:30 -0700235 return ListCommand::getPidInfoCached(serverPid);
236 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700237
Yifan Hong93b8bff2017-09-14 16:02:52 -0700238 MOCK_METHOD0(postprocess, void());
Devin Moorec03e3aa2020-12-11 15:11:17 -0800239 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
Yifan Hong8bf73162017-09-07 18:06:13 -0700240 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongf31aa052018-02-02 15:17:51 -0800241 MOCK_METHOD1(getPartition, Partition(pid_t));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700242
243 MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
244 MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
245 MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
246 MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700247};
248
249class ListParseArgsTest : public ::testing::Test {
250public:
251 void SetUp() override {
252 mockLshal = std::make_unique<NiceMock<MockLshal>>();
253 mockList = std::make_unique<MockListCommand>(mockLshal.get());
Yifan Hongc4430912018-06-27 16:48:34 -0700254 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700255 // ListCommand::parseArgs should parse arguments from the second element
256 optind = 1;
257 }
258 std::unique_ptr<MockLshal> mockLshal;
259 std::unique_ptr<MockListCommand> mockList;
Yifan Hongc4430912018-06-27 16:48:34 -0700260 std::stringstream err;
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700261};
262
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700263TEST_F(ListParseArgsTest, Args) {
264 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
265 mockList->forEachTable([](const Table& table) {
266 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
267 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
268 table.getSelectedColumns());
269 });
Yifan Hongc4430912018-06-27 16:48:34 -0700270 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700271}
272
273TEST_F(ListParseArgsTest, Cmds) {
274 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
275 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700276 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
277 << "should not print server PID with -m";
278 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
279 << "should not print client PIDs with -m";
280 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
281 << "should print server cmd with -m";
282 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
283 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700284 });
Yifan Hongc4430912018-06-27 16:48:34 -0700285 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700286}
287
288TEST_F(ListParseArgsTest, DebugAndNeat) {
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700289 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
Yifan Hongc4430912018-06-27 16:48:34 -0700290 EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700291}
292
Yifan Hong8bf73162017-09-07 18:06:13 -0700293/// Fetch Test
294
295// A set of deterministic functions to generate fake debug infos.
296static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
297static std::vector<pid_t> getClients(pid_t serverId) {
298 return {serverId + 1, serverId + 3};
299}
Devin Moorec03e3aa2020-12-11 15:11:17 -0800300static BinderPidInfo getPidInfoFromId(pid_t serverId) {
301 BinderPidInfo info;
Yifan Hong8bf73162017-09-07 18:06:13 -0700302 info.refPids[getPtr(serverId)] = getClients(serverId);
303 info.threadUsage = 10 + serverId;
304 info.threadCount = 20 + serverId;
305 return info;
306}
307static std::string getInterfaceName(pid_t serverId) {
308 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
309}
310static std::string getInstanceName(pid_t serverId) {
311 return std::to_string(serverId);
312}
313static pid_t getIdFromInstanceName(const hidl_string& instance) {
314 return atoi(instance.c_str());
315}
316static std::string getFqInstanceName(pid_t serverId) {
317 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
318}
319static std::string getCmdlineFromId(pid_t serverId) {
320 if (serverId == NO_PID) return "";
321 return "command_line_" + std::to_string(serverId);
322}
Yifan Hongfee209d2017-09-14 18:23:38 -0700323static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
324static hidl_hash getHashFromId(pid_t serverId) {
325 hidl_hash hash;
326 bool isReleased = getIsReleasedFromId(serverId);
327 for (size_t i = 0; i < hash.size(); ++i) {
328 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
329 }
330 return hash;
331}
Yifan Hong8bf73162017-09-07 18:06:13 -0700332
333// Fake service returned by mocked IServiceManager::get.
334class TestService : public IBase {
335public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800336 explicit TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700337 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700338 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
339 return hardware::Void();
340 }
341 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
342 cb({getInterfaceName(mId), IBase::descriptor});
343 return hardware::Void();
344 }
345 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
346 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700347 return hardware::Void();
348 }
349private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700350 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700351};
352
353class ListTest : public ::testing::Test {
354public:
Yifan Hong13ba0a92018-06-25 16:15:56 -0700355 virtual void SetUp() override {
Yifan Hong8bf73162017-09-07 18:06:13 -0700356 initMockServiceManager();
357 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
358 initMockList();
359 }
360
361 void initMockList() {
362 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
363 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
Devin Moorec03e3aa2020-12-11 15:11:17 -0800364 [](pid_t serverPid, BinderPidInfo* info) {
Yifan Hong8bf73162017-09-07 18:06:13 -0700365 *info = getPidInfoFromId(serverPid);
366 return true;
367 }));
368 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700369 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
370 mockList->internalPostprocess();
371 size_t i = 0;
372 mockList->forEachTable([&](Table& table) {
373 table.setDescription("[fake description " + std::to_string(i++) + "]");
374 });
375 }));
Yifan Hongf31aa052018-02-02 15:17:51 -0800376 ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700377
378 ON_CALL(*mockList, getDeviceManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700379 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700380 ON_CALL(*mockList, getDeviceMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700381 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700382 ON_CALL(*mockList, getFrameworkManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700383 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700384 ON_CALL(*mockList, getFrameworkMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700385 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hong8bf73162017-09-07 18:06:13 -0700386 }
387
388 void initMockServiceManager() {
389 serviceManager = new testing::NiceMock<MockServiceManager>();
390 passthruManager = new testing::NiceMock<MockServiceManager>();
391 using A = DebugInfo::Architecture;
392 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
393 [] (IServiceManager::list_cb cb) {
394 cb({ getFqInstanceName(1), getFqInstanceName(2) });
395 return hardware::Void();
396 }));
397
398 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
399 [&](const hidl_string&, const hidl_string& instance) {
400 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700401 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700402 }));
403
404 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
405 [] (IServiceManager::debugDump_cb cb) {
406 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
407 getClients(3), A::IS_32BIT},
408 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
409 getClients(4), A::IS_32BIT}});
410 return hardware::Void();
411 }));
412
413 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
414 [] (IServiceManager::debugDump_cb cb) {
415 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
416 getClients(5), A::IS_32BIT},
417 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
418 getClients(6), A::IS_32BIT}});
419 return hardware::Void();
420 }));
421 }
422
423 std::stringstream err;
424 std::stringstream out;
425 std::unique_ptr<Lshal> lshal;
426 std::unique_ptr<MockListCommand> mockList;
427 sp<MockServiceManager> serviceManager;
428 sp<MockServiceManager> passthruManager;
429};
430
Yifan Hong1243dde2017-09-14 17:49:30 -0700431TEST_F(ListTest, GetPidInfoCached) {
432 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
433
434 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
435 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
436}
437
Yifan Hong8bf73162017-09-07 18:06:13 -0700438TEST_F(ListTest, Fetch) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700439 optind = 1; // mimic Lshal::parseArg()
440 ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
441 ASSERT_EQ(0u, mockList->fetch());
Yifan Hong0ad64f52018-05-25 15:29:17 -0700442 vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
443 vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
444 std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
445 passthrough, passthrough, passthrough}};
Yifan Hong13ba0a92018-06-25 16:15:56 -0700446 int i = 0;
Yifan Hong8bf73162017-09-07 18:06:13 -0700447 mockList->forEachTable([&](const Table& table) {
Yifan Hong8bf73162017-09-07 18:06:13 -0700448 for (const auto& entry : table) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700449 if (i >= transportArchs.size()) {
450 break;
451 }
452
453 int id = i + 1;
454 auto transport = transportArchs.at(i).transport;
Yifan Hong8bf73162017-09-07 18:06:13 -0700455 TableEntry expected{
456 .interfaceName = getFqInstanceName(id),
457 .transport = transport,
Yifan Hong8304e412018-05-25 15:05:36 -0700458 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
459 .threadUsage =
460 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
461 .threadCount =
462 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
Yifan Hong8bf73162017-09-07 18:06:13 -0700463 .serverCmdline = {},
Yifan Hong8304e412018-05-25 15:05:36 -0700464 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
Yifan Hong8bf73162017-09-07 18:06:13 -0700465 .clientPids = getClients(id),
466 .clientCmdlines = {},
Yifan Hong13ba0a92018-06-25 16:15:56 -0700467 .arch = transportArchs.at(i).arch,
Yifan Hong8bf73162017-09-07 18:06:13 -0700468 };
469 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
470
Yifan Hong13ba0a92018-06-25 16:15:56 -0700471 ++i;
Yifan Hong8bf73162017-09-07 18:06:13 -0700472 }
473 });
474
Yifan Hong13ba0a92018-06-25 16:15:56 -0700475 EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
476
Yifan Hong8bf73162017-09-07 18:06:13 -0700477}
478
479TEST_F(ListTest, DumpVintf) {
Yifan Hong29b35b62020-10-14 21:17:07 -0700480 const std::string expected = " <hal format=\"hidl\">\n"
Yifan Hongb2d096a2018-05-01 15:25:23 -0700481 " <name>a.h.foo1</name>\n"
482 " <transport>hwbinder</transport>\n"
483 " <fqname>@1.0::IFoo/1</fqname>\n"
484 " </hal>\n"
485 " <hal format=\"hidl\">\n"
486 " <name>a.h.foo2</name>\n"
487 " <transport>hwbinder</transport>\n"
488 " <fqname>@2.0::IFoo/2</fqname>\n"
489 " </hal>\n"
490 " <hal format=\"hidl\">\n"
491 " <name>a.h.foo3</name>\n"
492 " <transport arch=\"32\">passthrough</transport>\n"
493 " <fqname>@3.0::IFoo/3</fqname>\n"
494 " </hal>\n"
495 " <hal format=\"hidl\">\n"
496 " <name>a.h.foo4</name>\n"
497 " <transport arch=\"32\">passthrough</transport>\n"
498 " <fqname>@4.0::IFoo/4</fqname>\n"
Yifan Hong29b35b62020-10-14 21:17:07 -0700499 " </hal>\n";
Yifan Hong8bf73162017-09-07 18:06:13 -0700500
501 optind = 1; // mimic Lshal::parseArg()
502 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
Yifan Hongb2d096a2018-05-01 15:25:23 -0700503 auto output = out.str();
504 EXPECT_THAT(output, HasSubstr(expected));
505 EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
506 EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
Yifan Hong8bf73162017-09-07 18:06:13 -0700507 EXPECT_EQ("", err.str());
508
Yifan Hong24d03042021-04-05 18:34:59 -0700509 std::string error;
Yifan Hong8bf73162017-09-07 18:06:13 -0700510 vintf::HalManifest m;
Yifan Honga96f87f2021-04-16 18:59:27 -0700511 EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
Yifan Hong24d03042021-04-05 18:34:59 -0700512 << "--init-vintf does not emit valid HAL manifest: " << error;
Yifan Hong8bf73162017-09-07 18:06:13 -0700513}
514
Yifan Hongfee209d2017-09-14 18:23:38 -0700515// test default columns
516TEST_F(ListTest, DumpDefault) {
517 const std::string expected =
518 "[fake description 0]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700519 "VINTF R Interface Thread Use Server Clients\n"
520 "X N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
521 "X Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700522 "\n"
523 "[fake description 1]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700524 "VINTF R Interface Thread Use Server Clients\n"
525 "X ? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
526 "X ? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700527 "\n"
528 "[fake description 2]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700529 "VINTF R Interface Thread Use Server Clients\n"
530 "X ? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
531 "X ? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700532 "\n";
533
534 optind = 1; // mimic Lshal::parseArg()
535 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
536 EXPECT_EQ(expected, out.str());
537 EXPECT_EQ("", err.str());
538}
539
540TEST_F(ListTest, DumpHash) {
541 const std::string expected =
542 "[fake description 0]\n"
543 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700544 "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700545 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
546 "\n"
547 "[fake description 1]\n"
548 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700549 "a.h.foo3@3.0::IFoo/3 ? \n"
550 "a.h.foo4@4.0::IFoo/4 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700551 "\n"
552 "[fake description 2]\n"
553 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700554 "a.h.foo5@5.0::IFoo/5 ? \n"
555 "a.h.foo6@6.0::IFoo/6 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700556 "\n";
557
558 optind = 1; // mimic Lshal::parseArg()
559 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
560 EXPECT_EQ(expected, out.str());
561 EXPECT_EQ("", err.str());
562}
563
Yifan Hong8bf73162017-09-07 18:06:13 -0700564TEST_F(ListTest, Dump) {
565 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700566 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700567 "Interface Transport Arch Thread Use Server PTR Clients\n"
568 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
569 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
570 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700571 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700572 "Interface Transport Arch Thread Use Server PTR Clients\n"
573 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
574 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
575 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700576 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700577 "Interface Transport Arch Thread Use Server PTR Clients\n"
578 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
579 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
580 "\n";
581
582 optind = 1; // mimic Lshal::parseArg()
583 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
584 EXPECT_EQ(expected, out.str());
585 EXPECT_EQ("", err.str());
586}
587
588TEST_F(ListTest, DumpCmdline) {
589 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700590 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700591 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
592 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
593 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
594 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700595 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700596 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
597 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
598 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
599 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700600 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700601 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
602 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
603 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
604 "\n";
605
606 optind = 1; // mimic Lshal::parseArg()
607 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
608 EXPECT_EQ(expected, out.str());
609 EXPECT_EQ("", err.str());
610}
611
612TEST_F(ListTest, DumpNeat) {
613 const std::string expected =
614 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
615 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
616 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
617 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
618 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
619 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
620
621 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700622 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700623 EXPECT_EQ(expected, out.str());
624 EXPECT_EQ("", err.str());
625}
Yifan Honga8bedc62017-09-08 18:00:31 -0700626
Nirav Atrecce988d2018-05-16 11:14:46 -0700627TEST_F(ListTest, DumpSingleHalType) {
628 const std::string expected =
629 "[fake description 0]\n"
630 "Interface Transport Arch Thread Use Server PTR Clients\n"
631 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
632 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
633 "\n";
634
635 optind = 1; // mimic Lshal::parseArg()
636 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
637 EXPECT_EQ(expected, out.str());
638 EXPECT_EQ("", err.str());
639}
640
641TEST_F(ListTest, DumpReorderedHalTypes) {
642 const std::string expected =
643 "[fake description 0]\n"
644 "Interface Transport Arch Thread Use Server PTR Clients\n"
645 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
646 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
647 "\n"
648 "[fake description 1]\n"
649 "Interface Transport Arch Thread Use Server PTR Clients\n"
650 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
651 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
652 "\n"
653 "[fake description 2]\n"
654 "Interface Transport Arch Thread Use Server PTR Clients\n"
655 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
656 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
657 "\n";
658
659 optind = 1; // mimic Lshal::parseArg()
660 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
661 "--types=passthrough_libs", "--types=binderized"})));
662 EXPECT_EQ(expected, out.str());
663 EXPECT_EQ("", err.str());
664}
665
666TEST_F(ListTest, DumpAbbreviatedHalTypes) {
667 const std::string expected =
668 "[fake description 0]\n"
669 "Interface Transport Arch Thread Use Server PTR Clients\n"
670 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
671 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
672 "\n"
673 "[fake description 1]\n"
674 "Interface Transport Arch Thread Use Server PTR Clients\n"
675 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
676 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
677 "\n";
678
679 optind = 1; // mimic Lshal::parseArg()
680 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
681 EXPECT_EQ(expected, out.str());
682 EXPECT_EQ("", err.str());
683}
684
685TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
686 const std::string expected =
687 "[fake description 0]\n"
688 "Interface Transport Arch Thread Use Server PTR Clients\n"
689 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
690 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
691 "\n"
692 "[fake description 1]\n"
693 "Interface Transport Arch Thread Use Server PTR Clients\n"
694 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
695 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
696 "\n";
697
698 optind = 1; // mimic Lshal::parseArg()
699 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
700 "--types=passthrough_libs,passthrough_clients"})));
701 EXPECT_EQ(expected, out.str());
702 EXPECT_EQ("", err.str());
703}
704
705TEST_F(ListTest, UnknownHalType) {
706 optind = 1; // mimic Lshal::parseArg()
Yifan Hong30528a22020-08-07 18:24:06 -0700707 EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"})));
708 EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r"));
Nirav Atrecce988d2018-05-16 11:14:46 -0700709}
710
Yifan Hongbdf44f82018-05-25 14:20:00 -0700711TEST_F(ListTest, Vintf) {
712 std::string deviceManifestXml =
713 "<manifest version=\"1.0\" type=\"device\">\n"
714 " <hal>\n"
715 " <name>a.h.foo1</name>\n"
716 " <transport>hwbinder</transport>\n"
717 " <fqname>@1.0::IFoo/1</fqname>\n"
718 " </hal>\n"
719 " <hal>\n"
720 " <name>a.h.foo3</name>\n"
721 " <transport arch=\"32+64\">passthrough</transport>\n"
722 " <fqname>@3.0::IFoo/3</fqname>\n"
723 " </hal>\n"
724 "</manifest>\n";
725 std::string frameworkManifestXml =
726 "<manifest version=\"1.0\" type=\"framework\">\n"
727 " <hal>\n"
728 " <name>a.h.foo5</name>\n"
729 " <transport arch=\"32\">passthrough</transport>\n"
730 " <fqname>@5.0::IFoo/5</fqname>\n"
731 " </hal>\n"
732 "</manifest>\n";
733 std::string deviceMatrixXml =
734 "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
735 " <hal>\n"
736 " <name>a.h.foo5</name>\n"
737 " <version>5.0</version>\n"
738 " <interface>\n"
739 " <name>IFoo</name>\n"
740 " <instance>5</instance>\n"
741 " </interface>\n"
742 " </hal>\n"
743 "</compatibility-matrix>\n";
744 std::string frameworkMatrixXml =
745 "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
746 " <hal>\n"
747 " <name>a.h.foo1</name>\n"
748 " <version>1.0</version>\n"
749 " <interface>\n"
750 " <name>IFoo</name>\n"
751 " <instance>1</instance>\n"
752 " </interface>\n"
753 " </hal>\n"
754 " <hal>\n"
755 " <name>a.h.foo3</name>\n"
756 " <version>3.0</version>\n"
757 " <interface>\n"
758 " <name>IFoo</name>\n"
759 " <instance>3</instance>\n"
760 " </interface>\n"
761 " </hal>\n"
762 "</compatibility-matrix>\n";
763
764 std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
765 "X a.h.foo2@2.0::IFoo/2\n"
766 "DM,FC a.h.foo3@3.0::IFoo/3\n"
767 "X a.h.foo4@4.0::IFoo/4\n"
768 "DC,FM a.h.foo5@5.0::IFoo/5\n"
769 "X a.h.foo6@6.0::IFoo/6\n";
770
771 auto deviceManifest = std::make_shared<HalManifest>();
772 auto frameworkManifest = std::make_shared<HalManifest>();
773 auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
774 auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
775
Yifan Honga96f87f2021-04-16 18:59:27 -0700776 ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
777 ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
778 ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
779 ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700780
781 ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
782 ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
783 ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
784 ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
785
786 optind = 1; // mimic Lshal::parseArg()
787 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
788 EXPECT_THAT(out.str(), HasSubstr(expected));
789 EXPECT_EQ("", err.str());
790}
791
Yifan Hong30528a22020-08-07 18:24:06 -0700792TEST_F(ListTest, AllColumns) {
793 // clang-format off
794 const std::string expected =
795 "[fake description 0]\n"
796 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
797 "a.h.foo1@1.0::IFoo/1 hwbinder 1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive 2 4\n"
798 "a.h.foo2@2.0::IFoo/2 hwbinder 2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive 3 5\n"
799 "\n"
800 "[fake description 1]\n"
801 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
802 "a.h.foo3@3.0::IFoo/3 passthrough N/A N/A 32 N/A ? X N/A 4 6\n"
803 "a.h.foo4@4.0::IFoo/4 passthrough N/A N/A 32 N/A ? X N/A 5 7\n"
804 "\n"
805 "[fake description 2]\n"
806 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
807 "a.h.foo5@5.0::IFoo/5 passthrough N/A N/A 32 N/A ? X N/A 6 8\n"
808 "a.h.foo6@6.0::IFoo/6 passthrough N/A N/A 32 N/A ? X N/A 7 9\n"
809 "\n";
810 // clang-format on
811
812 optind = 1; // mimic Lshal::parseArg()
813 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"})));
814 EXPECT_EQ(expected, out.str());
815 EXPECT_EQ("", err.str());
816}
817
818TEST_F(ListTest, AllColumnsWithCmd) {
819 // clang-format off
820 const std::string expected =
821 "[fake description 0]\n"
822 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
823 "a.h.foo1@1.0::IFoo/1 hwbinder command_line_1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive command_line_2;command_line_4\n"
824 "a.h.foo2@2.0::IFoo/2 hwbinder command_line_2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive command_line_3;command_line_5\n"
825 "\n"
826 "[fake description 1]\n"
827 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
828 "a.h.foo3@3.0::IFoo/3 passthrough N/A 32 N/A ? X N/A command_line_4;command_line_6\n"
829 "a.h.foo4@4.0::IFoo/4 passthrough N/A 32 N/A ? X N/A command_line_5;command_line_7\n"
830 "\n"
831 "[fake description 2]\n"
832 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
833 "a.h.foo5@5.0::IFoo/5 passthrough N/A 32 N/A ? X N/A command_line_6;command_line_8\n"
834 "a.h.foo6@6.0::IFoo/6 passthrough N/A 32 N/A ? X N/A command_line_7;command_line_9\n"
835 "\n";
836 // clang-format on
837
838 optind = 1; // mimic Lshal::parseArg()
839 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"})));
840 EXPECT_EQ(expected, out.str());
841 EXPECT_EQ("", err.str());
842}
843
844TEST_F(ListTest, AllSections) {
845 optind = 1; // mimic Lshal::parseArg()
846 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"})));
847 using HalTypeBase = std::underlying_type_t<HalType>;
848 for (HalTypeBase i = 0; i < static_cast<HalTypeBase>(HalType::LAST); ++i) {
849 EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]"));
850 }
851 EXPECT_THAT(out.str(),
852 Not(HasSubstr("[fake description " +
853 std::to_string(static_cast<HalTypeBase>(HalType::LAST)) + "]")));
854 EXPECT_EQ("", err.str());
855}
856
Yifan Hong6884b872020-07-09 16:38:18 -0700857// Fake service returned by mocked IServiceManager::get for DumpDebug.
858// The interfaceChain and getHashChain functions returns
859// foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
860class InheritingService : public IBase {
861public:
862 explicit InheritingService(pid_t id) : mId(id) {}
863 android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
864 cb(getInterfaceName(mId));
865 return hardware::Void();
866 }
867 android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
868 std::vector<hidl_string> ret;
869 for (auto i = mId; i > 0; --i) {
870 ret.push_back(getInterfaceName(i));
871 }
872 ret.push_back(IBase::descriptor);
873 cb(ret);
874 return hardware::Void();
875 }
876 android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
877 std::vector<hidl_hash> ret;
878 for (auto i = mId; i > 0; --i) {
879 ret.push_back(getHashFromId(i));
880 }
881 ret.push_back(getHashFromId(0xff));
882 cb(ret);
883 return hardware::Void();
884 }
885 android::hardware::Return<void> debug(const hidl_handle& hh,
886 const hidl_vec<hidl_string>&) override {
887 const native_handle_t* handle = hh.getNativeHandle();
888 if (handle->numFds < 1) {
889 return Void();
890 }
891 int fd = handle->data[0];
892 std::string content = "debug info for ";
893 content += getInterfaceName(mId);
894 ssize_t written = write(fd, content.c_str(), content.size());
895 if (written != (ssize_t)content.size()) {
896 LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
897 << content.size() << " bytes, errno = " << errno;
898 }
899 return Void();
900 }
901
902private:
903 pid_t mId;
904};
905
906TEST_F(ListTest, DumpDebug) {
907 size_t inheritanceLevel = 3;
908 sp<IBase> service = new InheritingService(inheritanceLevel);
909
910 EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
911 std::vector<hidl_string> ret;
912 for (auto i = 1; i <= inheritanceLevel; ++i) {
913 ret.push_back(getInterfaceName(i) + "/default");
914 }
915 cb(ret);
916 return hardware::Void();
917 }));
918 EXPECT_CALL(*serviceManager, get(_, _))
919 .WillRepeatedly(
920 Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
921 int id = getIdFromInstanceName(instance);
922 if (id > inheritanceLevel) return nullptr;
923 return sp<IBase>(service);
924 }));
925
926 const std::string expected = "[fake description 0]\n"
927 "Interface\n"
928 "a.h.foo1@1.0::IFoo/default\n"
929 "[See a.h.foo3@3.0::IFoo/default]\n"
930 "a.h.foo2@2.0::IFoo/default\n"
931 "[See a.h.foo3@3.0::IFoo/default]\n"
932 "a.h.foo3@3.0::IFoo/default\n"
933 "debug info for a.h.foo3@3.0::IFoo\n"
934 "\n";
935
936 optind = 1; // mimic Lshal::parseArg()
937 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
938 EXPECT_EQ(expected, out.str());
939 EXPECT_EQ("", err.str());
940}
941
Yifan Hong13ba0a92018-06-25 16:15:56 -0700942class ListVintfTest : public ListTest {
943public:
944 virtual void SetUp() override {
945 ListTest::SetUp();
946 const std::string mockManifestXml =
947 "<manifest version=\"1.0\" type=\"device\">\n"
948 " <hal format=\"hidl\">\n"
949 " <name>a.h.foo1</name>\n"
950 " <transport>hwbinder</transport>\n"
951 " <fqname>@1.0::IFoo/1</fqname>\n"
952 " </hal>\n"
953 " <hal format=\"hidl\">\n"
954 " <name>a.h.bar1</name>\n"
955 " <transport>hwbinder</transport>\n"
956 " <fqname>@1.0::IBar/1</fqname>\n"
957 " </hal>\n"
958 " <hal format=\"hidl\">\n"
959 " <name>a.h.bar2</name>\n"
960 " <transport arch=\"32+64\">passthrough</transport>\n"
961 " <fqname>@2.0::IBar/2</fqname>\n"
962 " </hal>\n"
963 "</manifest>";
964 auto manifest = std::make_shared<HalManifest>();
Yifan Honga96f87f2021-04-16 18:59:27 -0700965 EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
Yifan Hong13ba0a92018-06-25 16:15:56 -0700966 EXPECT_CALL(*mockList, getDeviceManifest())
967 .Times(AnyNumber())
968 .WillRepeatedly(Return(manifest));
969 }
970};
971
972TEST_F(ListVintfTest, ManifestHals) {
973 optind = 1; // mimic Lshal::parseArg()
974 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
975 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
976 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
977 EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder ?"));
978 EXPECT_EQ("", err.str());
979}
980
Yifan Hong3212f172018-06-28 12:39:50 -0700981TEST_F(ListVintfTest, Lazy) {
982 optind = 1; // mimic Lshal::parseArg()
983 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
984 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
985 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
986 EXPECT_EQ("", err.str());
987}
988
989TEST_F(ListVintfTest, NoLazy) {
990 optind = 1; // mimic Lshal::parseArg()
991 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
992 EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
993 EXPECT_EQ("", err.str());
994}
995
Yifan Honga8bedc62017-09-08 18:00:31 -0700996class HelpTest : public ::testing::Test {
997public:
998 void SetUp() override {
999 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
1000 new MockServiceManager() /* passthruManager */);
1001 }
1002
1003 std::stringstream err;
1004 std::stringstream out;
1005 std::unique_ptr<Lshal> lshal;
1006};
1007
1008TEST_F(HelpTest, GlobalUsage) {
1009 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
1010 std::string errStr = err.str();
1011 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
1012 << "`lshal --help` does not contain global usage";
1013 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
1014 << "`lshal --help` does not contain usage for 'list' command";
1015 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
1016 << "`lshal --help` does not contain usage for 'debug' command";
1017 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
1018 << "`lshal --help` does not contain usage for 'help' command";
1019
1020 err.str("");
1021 (void)callMain(lshal, {"lshal", "help"}); // ignore return
1022 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
1023
1024 err.str("");
1025 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
1026 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1027 EXPECT_THAT(err.str(), EndsWith(errStr))
1028 << "`lshal --unknown-option` should have the same output as `lshal --help`";
1029 EXPECT_EQ("", out.str());
1030}
1031
1032TEST_F(HelpTest, UnknownOptionList1) {
1033 (void)callMain(lshal, {"lshal", "help", "list"});
1034 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1035 << "`lshal help list` does not contain usage for 'list' command";
1036}
1037
1038TEST_F(HelpTest, UnknownOptionList2) {
1039 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
1040 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1041 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1042 << "`lshal list --unknown-option` does not contain usage for 'list' command";
1043 EXPECT_EQ("", out.str());
1044}
1045
1046TEST_F(HelpTest, UnknownOptionHelp1) {
1047 (void)callMain(lshal, {"lshal", "help", "help"});
1048 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1049 << "`lshal help help` does not contain usage for 'help' command";
1050}
1051
1052TEST_F(HelpTest, UnknownOptionHelp2) {
1053 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
1054 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1055 << "`lshal help --unknown-option` does not contain usage for 'help' command";
1056 EXPECT_EQ("", out.str());
1057}
1058
Yifan Hong9881df92017-05-10 14:33:05 -07001059} // namespace lshal
1060} // namespace android
1061
1062int main(int argc, char **argv) {
1063 ::testing::InitGoogleMock(&argc, argv);
1064 return RUN_ALL_TESTS();
1065}