blob: 9964888233805914f9ccaeafc8866d453308f96b [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;
50using android::vintf::gCompatibilityMatrixConverter;
51using android::vintf::gHalManifestConverter;
52using android::vintf::HalManifest;
Yifan Hong8304e412018-05-25 15:05:36 -070053using android::vintf::Transport;
Yifan Hongbdf44f82018-05-25 14:20:00 -070054using android::vintf::VintfObject;
Yifan Hong9881df92017-05-10 14:33:05 -070055
Yifan Hong8bf73162017-09-07 18:06:13 -070056using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
57
Yifan Hongfee209d2017-09-14 18:23:38 -070058using hidl_hash = hidl_array<uint8_t, 32>;
59
Yifan Hong9881df92017-05-10 14:33:05 -070060namespace android {
61namespace hardware {
62namespace tests {
Yifan Hong5cceea82020-07-09 19:34:58 -070063namespace inheritance {
Yifan Hong9881df92017-05-10 14:33:05 -070064namespace V1_0 {
65namespace implementation {
Yifan Hong5cceea82020-07-09 19:34:58 -070066struct Child : android::hardware::tests::inheritance::V1_0::IChild {
67 ::android::hardware::Return<void> doChild() override { return Void(); }
68 ::android::hardware::Return<void> doParent() override { return Void(); }
69 ::android::hardware::Return<void> doGrandparent() override { return Void(); }
70
Yifan Hong9881df92017-05-10 14:33:05 -070071 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
72 const native_handle_t *handle = hh.getNativeHandle();
73 if (handle->numFds < 1) {
74 return Void();
75 }
76 int fd = handle->data[0];
77 std::string content{descriptor};
78 for (const auto &option : options) {
79 content += "\n";
80 content += option.c_str();
81 }
82 ssize_t written = write(fd, content.c_str(), content.size());
83 if (written != (ssize_t)content.size()) {
Yifan Hong5cceea82020-07-09 19:34:58 -070084 LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
Yifan Hong9881df92017-05-10 14:33:05 -070085 << content.size() << " bytes, errno = " << errno;
86 }
87 return Void();
88 }
89};
90
91} // namespace implementation
92} // namespace V1_0
Yifan Hong5cceea82020-07-09 19:34:58 -070093} // namespace inheritance
Yifan Hong9881df92017-05-10 14:33:05 -070094} // namespace tests
95} // namespace hardware
96
97namespace lshal {
98
Yifan Hong9881df92017-05-10 14:33:05 -070099class MockServiceManager : public IServiceManager {
100public:
101 template<typename T>
102 using R = ::android::hardware::Return<T>;
103 using String = const hidl_string&;
104 ~MockServiceManager() = default;
105
106#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
107
108 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
109 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
110 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
111 MOCK_METHOD_CB(list);
112 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
113 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
114 MOCK_METHOD_CB(debugDump);
115 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
116 MOCK_METHOD_CB(interfaceChain);
117 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
118 MOCK_METHOD_CB(interfaceDescriptor);
119 MOCK_METHOD_CB(getHashChain);
120 MOCK_METHOD0(setHalInstrumentation, R<void>());
121 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
122 MOCK_METHOD0(ping, R<void>());
123 MOCK_METHOD_CB(getDebugInfo);
124 MOCK_METHOD0(notifySyspropsChanged, R<void>());
125 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
126
127};
128
Yifan Hongbf20a262017-09-07 11:10:58 -0700129class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700130public:
131 void SetUp() override {
Yifan Hong5cceea82020-07-09 19:34:58 -0700132 using ::android::hardware::tests::inheritance::V1_0::IChild;
133 using ::android::hardware::tests::inheritance::V1_0::IParent;
134 using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
135 using ::android::hardware::tests::inheritance::V1_0::implementation::Child;
Yifan Hong9881df92017-05-10 14:33:05 -0700136
137 err.str("");
138 out.str("");
139 serviceManager = new testing::NiceMock<MockServiceManager>();
Yifan Hong5cceea82020-07-09 19:34:58 -0700140 ON_CALL(*serviceManager, get(_, _))
141 .WillByDefault(
142 Invoke([](const auto& iface,
143 const auto& inst) -> ::android::hardware::Return<sp<IBase>> {
144 if (inst != "default") return nullptr;
145 if (iface == IChild::descriptor || iface == IParent::descriptor ||
146 iface == IGrandparent::descriptor)
147 return new Child();
148 return nullptr;
149 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700150
151 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700152 }
153 void TearDown() override {}
154
155 std::stringstream err;
156 std::stringstream out;
157 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700158
159 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700160};
161
Yifan Hongbf20a262017-09-07 11:10:58 -0700162static Arg createArg(const std::vector<const char*>& args) {
163 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
164}
165
166template<typename T>
167static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
168 return lshal->main(createArg(args));
169}
170
171TEST_F(DebugTest, Debug) {
172 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700173 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700174 }));
Yifan Hong5cceea82020-07-09 19:34:58 -0700175 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nfoo\nbar"));
Yifan Hong9881df92017-05-10 14:33:05 -0700176 EXPECT_THAT(err.str(), IsEmpty());
177}
178
Yifan Hongbf20a262017-09-07 11:10:58 -0700179TEST_F(DebugTest, Debug2) {
180 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700181 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700182 }));
Yifan Hong5cceea82020-07-09 19:34:58 -0700183 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nbaz\nquux"));
Yifan Hong9881df92017-05-10 14:33:05 -0700184 EXPECT_THAT(err.str(), IsEmpty());
185}
186
Yifan Hongbf20a262017-09-07 11:10:58 -0700187TEST_F(DebugTest, Debug3) {
188 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700189 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700190 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700191 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
192}
193
Yifan Hong5cceea82020-07-09 19:34:58 -0700194TEST_F(DebugTest, DebugParent) {
195 EXPECT_EQ(0u, callMain(lshal, {
196 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
197 }));
198 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\ncalling parent"));
199 EXPECT_THAT(err.str(), IsEmpty());
200}
201
202TEST_F(DebugTest, DebugParentExclude) {
203 EXPECT_EQ(0u, callMain(lshal, {
204 "lshal", "debug", "-E", "android.hardware.tests.inheritance@1.0::IParent", "excluding"
205 }));
206 EXPECT_THAT(out.str(), IsEmpty());
207 EXPECT_THAT(err.str(), IsEmpty());
208}
209
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700210class MockLshal : public Lshal {
211public:
212 MockLshal() {}
213 ~MockLshal() = default;
214 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
215 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
216};
217
218// expose protected fields and methods for ListCommand
219class MockListCommand : public ListCommand {
220public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800221 explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700222
Yifan Honga8bedc62017-09-08 18:00:31 -0700223 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
224 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700225 void forEachTable(const std::function<void(Table &)> &f) {
226 return ListCommand::forEachTable(f);
227 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700228 void forEachTable(const std::function<void(const Table &)> &f) const {
229 return ListCommand::forEachTable(f);
230 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700231 Status fetch() { return ListCommand::fetch(); }
232 void dumpVintf(const NullableOStream<std::ostream>& out) {
233 return ListCommand::dumpVintf(out);
234 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700235 void internalPostprocess() { ListCommand::postprocess(); }
Yifan Hong1243dde2017-09-14 17:49:30 -0700236 const PidInfo* getPidInfoCached(pid_t serverPid) {
237 return ListCommand::getPidInfoCached(serverPid);
238 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700239
Yifan Hong93b8bff2017-09-14 16:02:52 -0700240 MOCK_METHOD0(postprocess, void());
Yifan Hong8bf73162017-09-07 18:06:13 -0700241 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
242 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongf31aa052018-02-02 15:17:51 -0800243 MOCK_METHOD1(getPartition, Partition(pid_t));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700244
245 MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
246 MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
247 MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
248 MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700249};
250
251class ListParseArgsTest : public ::testing::Test {
252public:
253 void SetUp() override {
254 mockLshal = std::make_unique<NiceMock<MockLshal>>();
255 mockList = std::make_unique<MockListCommand>(mockLshal.get());
Yifan Hongc4430912018-06-27 16:48:34 -0700256 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700257 // ListCommand::parseArgs should parse arguments from the second element
258 optind = 1;
259 }
260 std::unique_ptr<MockLshal> mockLshal;
261 std::unique_ptr<MockListCommand> mockList;
Yifan Hongc4430912018-06-27 16:48:34 -0700262 std::stringstream err;
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700263};
264
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700265TEST_F(ListParseArgsTest, Args) {
266 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
267 mockList->forEachTable([](const Table& table) {
268 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
269 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
270 table.getSelectedColumns());
271 });
Yifan Hongc4430912018-06-27 16:48:34 -0700272 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700273}
274
275TEST_F(ListParseArgsTest, Cmds) {
276 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
277 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700278 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
279 << "should not print server PID with -m";
280 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
281 << "should not print client PIDs with -m";
282 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
283 << "should print server cmd with -m";
284 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
285 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700286 });
Yifan Hongc4430912018-06-27 16:48:34 -0700287 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700288}
289
290TEST_F(ListParseArgsTest, DebugAndNeat) {
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700291 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
Yifan Hongc4430912018-06-27 16:48:34 -0700292 EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700293}
294
Yifan Hong8bf73162017-09-07 18:06:13 -0700295/// Fetch Test
296
297// A set of deterministic functions to generate fake debug infos.
298static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
299static std::vector<pid_t> getClients(pid_t serverId) {
300 return {serverId + 1, serverId + 3};
301}
302static PidInfo getPidInfoFromId(pid_t serverId) {
303 PidInfo info;
304 info.refPids[getPtr(serverId)] = getClients(serverId);
305 info.threadUsage = 10 + serverId;
306 info.threadCount = 20 + serverId;
307 return info;
308}
309static std::string getInterfaceName(pid_t serverId) {
310 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
311}
312static std::string getInstanceName(pid_t serverId) {
313 return std::to_string(serverId);
314}
315static pid_t getIdFromInstanceName(const hidl_string& instance) {
316 return atoi(instance.c_str());
317}
318static std::string getFqInstanceName(pid_t serverId) {
319 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
320}
321static std::string getCmdlineFromId(pid_t serverId) {
322 if (serverId == NO_PID) return "";
323 return "command_line_" + std::to_string(serverId);
324}
Yifan Hongfee209d2017-09-14 18:23:38 -0700325static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
326static hidl_hash getHashFromId(pid_t serverId) {
327 hidl_hash hash;
328 bool isReleased = getIsReleasedFromId(serverId);
329 for (size_t i = 0; i < hash.size(); ++i) {
330 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
331 }
332 return hash;
333}
Yifan Hong8bf73162017-09-07 18:06:13 -0700334
335// Fake service returned by mocked IServiceManager::get.
336class TestService : public IBase {
337public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800338 explicit TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700339 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700340 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
341 return hardware::Void();
342 }
343 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
344 cb({getInterfaceName(mId), IBase::descriptor});
345 return hardware::Void();
346 }
347 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
348 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700349 return hardware::Void();
350 }
351private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700352 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700353};
354
355class ListTest : public ::testing::Test {
356public:
Yifan Hong13ba0a92018-06-25 16:15:56 -0700357 virtual void SetUp() override {
Yifan Hong8bf73162017-09-07 18:06:13 -0700358 initMockServiceManager();
359 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
360 initMockList();
361 }
362
363 void initMockList() {
364 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
365 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
366 [](pid_t serverPid, PidInfo* info) {
367 *info = getPidInfoFromId(serverPid);
368 return true;
369 }));
370 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700371 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
372 mockList->internalPostprocess();
373 size_t i = 0;
374 mockList->forEachTable([&](Table& table) {
375 table.setDescription("[fake description " + std::to_string(i++) + "]");
376 });
377 }));
Yifan Hongf31aa052018-02-02 15:17:51 -0800378 ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700379
380 ON_CALL(*mockList, getDeviceManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700381 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700382 ON_CALL(*mockList, getDeviceMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700383 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700384 ON_CALL(*mockList, getFrameworkManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700385 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700386 ON_CALL(*mockList, getFrameworkMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700387 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hong8bf73162017-09-07 18:06:13 -0700388 }
389
390 void initMockServiceManager() {
391 serviceManager = new testing::NiceMock<MockServiceManager>();
392 passthruManager = new testing::NiceMock<MockServiceManager>();
393 using A = DebugInfo::Architecture;
394 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
395 [] (IServiceManager::list_cb cb) {
396 cb({ getFqInstanceName(1), getFqInstanceName(2) });
397 return hardware::Void();
398 }));
399
400 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
401 [&](const hidl_string&, const hidl_string& instance) {
402 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700403 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700404 }));
405
406 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
407 [] (IServiceManager::debugDump_cb cb) {
408 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
409 getClients(3), A::IS_32BIT},
410 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
411 getClients(4), A::IS_32BIT}});
412 return hardware::Void();
413 }));
414
415 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
416 [] (IServiceManager::debugDump_cb cb) {
417 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
418 getClients(5), A::IS_32BIT},
419 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
420 getClients(6), A::IS_32BIT}});
421 return hardware::Void();
422 }));
423 }
424
425 std::stringstream err;
426 std::stringstream out;
427 std::unique_ptr<Lshal> lshal;
428 std::unique_ptr<MockListCommand> mockList;
429 sp<MockServiceManager> serviceManager;
430 sp<MockServiceManager> passthruManager;
431};
432
Yifan Hong1243dde2017-09-14 17:49:30 -0700433TEST_F(ListTest, GetPidInfoCached) {
434 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
435
436 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
437 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
438}
439
Yifan Hong8bf73162017-09-07 18:06:13 -0700440TEST_F(ListTest, Fetch) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700441 optind = 1; // mimic Lshal::parseArg()
442 ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
443 ASSERT_EQ(0u, mockList->fetch());
Yifan Hong0ad64f52018-05-25 15:29:17 -0700444 vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
445 vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
446 std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
447 passthrough, passthrough, passthrough}};
Yifan Hong13ba0a92018-06-25 16:15:56 -0700448 int i = 0;
Yifan Hong8bf73162017-09-07 18:06:13 -0700449 mockList->forEachTable([&](const Table& table) {
Yifan Hong8bf73162017-09-07 18:06:13 -0700450 for (const auto& entry : table) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700451 if (i >= transportArchs.size()) {
452 break;
453 }
454
455 int id = i + 1;
456 auto transport = transportArchs.at(i).transport;
Yifan Hong8bf73162017-09-07 18:06:13 -0700457 TableEntry expected{
458 .interfaceName = getFqInstanceName(id),
459 .transport = transport,
Yifan Hong8304e412018-05-25 15:05:36 -0700460 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
461 .threadUsage =
462 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
463 .threadCount =
464 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
Yifan Hong8bf73162017-09-07 18:06:13 -0700465 .serverCmdline = {},
Yifan Hong8304e412018-05-25 15:05:36 -0700466 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
Yifan Hong8bf73162017-09-07 18:06:13 -0700467 .clientPids = getClients(id),
468 .clientCmdlines = {},
Yifan Hong13ba0a92018-06-25 16:15:56 -0700469 .arch = transportArchs.at(i).arch,
Yifan Hong8bf73162017-09-07 18:06:13 -0700470 };
471 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
472
Yifan Hong13ba0a92018-06-25 16:15:56 -0700473 ++i;
Yifan Hong8bf73162017-09-07 18:06:13 -0700474 }
475 });
476
Yifan Hong13ba0a92018-06-25 16:15:56 -0700477 EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
478
Yifan Hong8bf73162017-09-07 18:06:13 -0700479}
480
481TEST_F(ListTest, DumpVintf) {
Steven Morelandc3ba3a02019-09-09 10:41:49 -0700482 const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n"
Yifan Hongb2d096a2018-05-01 15:25:23 -0700483 " <hal format=\"hidl\">\n"
484 " <name>a.h.foo1</name>\n"
485 " <transport>hwbinder</transport>\n"
486 " <fqname>@1.0::IFoo/1</fqname>\n"
487 " </hal>\n"
488 " <hal format=\"hidl\">\n"
489 " <name>a.h.foo2</name>\n"
490 " <transport>hwbinder</transport>\n"
491 " <fqname>@2.0::IFoo/2</fqname>\n"
492 " </hal>\n"
493 " <hal format=\"hidl\">\n"
494 " <name>a.h.foo3</name>\n"
495 " <transport arch=\"32\">passthrough</transport>\n"
496 " <fqname>@3.0::IFoo/3</fqname>\n"
497 " </hal>\n"
498 " <hal format=\"hidl\">\n"
499 " <name>a.h.foo4</name>\n"
500 " <transport arch=\"32\">passthrough</transport>\n"
501 " <fqname>@4.0::IFoo/4</fqname>\n"
502 " </hal>\n"
503 "</manifest>";
Yifan Hong8bf73162017-09-07 18:06:13 -0700504
505 optind = 1; // mimic Lshal::parseArg()
506 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
Yifan Hongb2d096a2018-05-01 15:25:23 -0700507 auto output = out.str();
508 EXPECT_THAT(output, HasSubstr(expected));
509 EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
510 EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
Yifan Hong8bf73162017-09-07 18:06:13 -0700511 EXPECT_EQ("", err.str());
512
513 vintf::HalManifest m;
514 EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
515 << "--init-vintf does not emit valid HAL manifest: "
516 << vintf::gHalManifestConverter.lastError();
517}
518
Yifan Hongfee209d2017-09-14 18:23:38 -0700519// test default columns
520TEST_F(ListTest, DumpDefault) {
521 const std::string expected =
522 "[fake description 0]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700523 "VINTF R Interface Thread Use Server Clients\n"
524 "X N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
525 "X Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700526 "\n"
527 "[fake description 1]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700528 "VINTF R Interface Thread Use Server Clients\n"
529 "X ? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
530 "X ? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700531 "\n"
532 "[fake description 2]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700533 "VINTF R Interface Thread Use Server Clients\n"
534 "X ? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
535 "X ? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700536 "\n";
537
538 optind = 1; // mimic Lshal::parseArg()
539 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
540 EXPECT_EQ(expected, out.str());
541 EXPECT_EQ("", err.str());
542}
543
544TEST_F(ListTest, DumpHash) {
545 const std::string expected =
546 "[fake description 0]\n"
547 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700548 "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700549 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
550 "\n"
551 "[fake description 1]\n"
552 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700553 "a.h.foo3@3.0::IFoo/3 ? \n"
554 "a.h.foo4@4.0::IFoo/4 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700555 "\n"
556 "[fake description 2]\n"
557 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700558 "a.h.foo5@5.0::IFoo/5 ? \n"
559 "a.h.foo6@6.0::IFoo/6 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700560 "\n";
561
562 optind = 1; // mimic Lshal::parseArg()
563 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
564 EXPECT_EQ(expected, out.str());
565 EXPECT_EQ("", err.str());
566}
567
Yifan Hong8bf73162017-09-07 18:06:13 -0700568TEST_F(ListTest, Dump) {
569 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700570 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700571 "Interface Transport Arch Thread Use Server PTR Clients\n"
572 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
573 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
574 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700575 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700576 "Interface Transport Arch Thread Use Server PTR Clients\n"
577 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
578 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
579 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700580 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700581 "Interface Transport Arch Thread Use Server PTR Clients\n"
582 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
583 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
584 "\n";
585
586 optind = 1; // mimic Lshal::parseArg()
587 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
588 EXPECT_EQ(expected, out.str());
589 EXPECT_EQ("", err.str());
590}
591
592TEST_F(ListTest, DumpCmdline) {
593 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700594 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700595 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
596 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
597 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
598 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700599 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700600 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
601 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
602 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
603 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700604 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700605 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
606 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
607 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
608 "\n";
609
610 optind = 1; // mimic Lshal::parseArg()
611 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
612 EXPECT_EQ(expected, out.str());
613 EXPECT_EQ("", err.str());
614}
615
616TEST_F(ListTest, DumpNeat) {
617 const std::string expected =
618 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
619 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
620 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
621 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
622 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
623 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
624
625 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700626 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700627 EXPECT_EQ(expected, out.str());
628 EXPECT_EQ("", err.str());
629}
Yifan Honga8bedc62017-09-08 18:00:31 -0700630
Nirav Atrecce988d2018-05-16 11:14:46 -0700631TEST_F(ListTest, DumpSingleHalType) {
632 const std::string expected =
633 "[fake description 0]\n"
634 "Interface Transport Arch Thread Use Server PTR Clients\n"
635 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
636 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
637 "\n";
638
639 optind = 1; // mimic Lshal::parseArg()
640 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
641 EXPECT_EQ(expected, out.str());
642 EXPECT_EQ("", err.str());
643}
644
645TEST_F(ListTest, DumpReorderedHalTypes) {
646 const std::string expected =
647 "[fake description 0]\n"
648 "Interface Transport Arch Thread Use Server PTR Clients\n"
649 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
650 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
651 "\n"
652 "[fake description 1]\n"
653 "Interface Transport Arch Thread Use Server PTR Clients\n"
654 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
655 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
656 "\n"
657 "[fake description 2]\n"
658 "Interface Transport Arch Thread Use Server PTR Clients\n"
659 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
660 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
661 "\n";
662
663 optind = 1; // mimic Lshal::parseArg()
664 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
665 "--types=passthrough_libs", "--types=binderized"})));
666 EXPECT_EQ(expected, out.str());
667 EXPECT_EQ("", err.str());
668}
669
670TEST_F(ListTest, DumpAbbreviatedHalTypes) {
671 const std::string expected =
672 "[fake description 0]\n"
673 "Interface Transport Arch Thread Use Server PTR Clients\n"
674 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
675 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
676 "\n"
677 "[fake description 1]\n"
678 "Interface Transport Arch Thread Use Server PTR Clients\n"
679 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
680 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
681 "\n";
682
683 optind = 1; // mimic Lshal::parseArg()
684 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
685 EXPECT_EQ(expected, out.str());
686 EXPECT_EQ("", err.str());
687}
688
689TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
690 const std::string expected =
691 "[fake description 0]\n"
692 "Interface Transport Arch Thread Use Server PTR Clients\n"
693 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
694 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
695 "\n"
696 "[fake description 1]\n"
697 "Interface Transport Arch Thread Use Server PTR Clients\n"
698 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
699 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
700 "\n";
701
702 optind = 1; // mimic Lshal::parseArg()
703 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
704 "--types=passthrough_libs,passthrough_clients"})));
705 EXPECT_EQ(expected, out.str());
706 EXPECT_EQ("", err.str());
707}
708
709TEST_F(ListTest, UnknownHalType) {
710 optind = 1; // mimic Lshal::parseArg()
Yifan Hong30528a22020-08-07 18:24:06 -0700711 EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"})));
712 EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r"));
Nirav Atrecce988d2018-05-16 11:14:46 -0700713}
714
Yifan Hongbdf44f82018-05-25 14:20:00 -0700715TEST_F(ListTest, Vintf) {
716 std::string deviceManifestXml =
717 "<manifest version=\"1.0\" type=\"device\">\n"
718 " <hal>\n"
719 " <name>a.h.foo1</name>\n"
720 " <transport>hwbinder</transport>\n"
721 " <fqname>@1.0::IFoo/1</fqname>\n"
722 " </hal>\n"
723 " <hal>\n"
724 " <name>a.h.foo3</name>\n"
725 " <transport arch=\"32+64\">passthrough</transport>\n"
726 " <fqname>@3.0::IFoo/3</fqname>\n"
727 " </hal>\n"
728 "</manifest>\n";
729 std::string frameworkManifestXml =
730 "<manifest version=\"1.0\" type=\"framework\">\n"
731 " <hal>\n"
732 " <name>a.h.foo5</name>\n"
733 " <transport arch=\"32\">passthrough</transport>\n"
734 " <fqname>@5.0::IFoo/5</fqname>\n"
735 " </hal>\n"
736 "</manifest>\n";
737 std::string deviceMatrixXml =
738 "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
739 " <hal>\n"
740 " <name>a.h.foo5</name>\n"
741 " <version>5.0</version>\n"
742 " <interface>\n"
743 " <name>IFoo</name>\n"
744 " <instance>5</instance>\n"
745 " </interface>\n"
746 " </hal>\n"
747 "</compatibility-matrix>\n";
748 std::string frameworkMatrixXml =
749 "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
750 " <hal>\n"
751 " <name>a.h.foo1</name>\n"
752 " <version>1.0</version>\n"
753 " <interface>\n"
754 " <name>IFoo</name>\n"
755 " <instance>1</instance>\n"
756 " </interface>\n"
757 " </hal>\n"
758 " <hal>\n"
759 " <name>a.h.foo3</name>\n"
760 " <version>3.0</version>\n"
761 " <interface>\n"
762 " <name>IFoo</name>\n"
763 " <instance>3</instance>\n"
764 " </interface>\n"
765 " </hal>\n"
766 "</compatibility-matrix>\n";
767
768 std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
769 "X a.h.foo2@2.0::IFoo/2\n"
770 "DM,FC a.h.foo3@3.0::IFoo/3\n"
771 "X a.h.foo4@4.0::IFoo/4\n"
772 "DC,FM a.h.foo5@5.0::IFoo/5\n"
773 "X a.h.foo6@6.0::IFoo/6\n";
774
775 auto deviceManifest = std::make_shared<HalManifest>();
776 auto frameworkManifest = std::make_shared<HalManifest>();
777 auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
778 auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
779
780 ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
781 ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
782 ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
783 ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
784
785 ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
786 ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
787 ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
788 ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
789
790 optind = 1; // mimic Lshal::parseArg()
791 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
792 EXPECT_THAT(out.str(), HasSubstr(expected));
793 EXPECT_EQ("", err.str());
794}
795
Yifan Hong30528a22020-08-07 18:24:06 -0700796TEST_F(ListTest, AllColumns) {
797 // clang-format off
798 const std::string expected =
799 "[fake description 0]\n"
800 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
801 "a.h.foo1@1.0::IFoo/1 hwbinder 1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive 2 4\n"
802 "a.h.foo2@2.0::IFoo/2 hwbinder 2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive 3 5\n"
803 "\n"
804 "[fake description 1]\n"
805 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
806 "a.h.foo3@3.0::IFoo/3 passthrough N/A N/A 32 N/A ? X N/A 4 6\n"
807 "a.h.foo4@4.0::IFoo/4 passthrough N/A N/A 32 N/A ? X N/A 5 7\n"
808 "\n"
809 "[fake description 2]\n"
810 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
811 "a.h.foo5@5.0::IFoo/5 passthrough N/A N/A 32 N/A ? X N/A 6 8\n"
812 "a.h.foo6@6.0::IFoo/6 passthrough N/A N/A 32 N/A ? X N/A 7 9\n"
813 "\n";
814 // clang-format on
815
816 optind = 1; // mimic Lshal::parseArg()
817 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"})));
818 EXPECT_EQ(expected, out.str());
819 EXPECT_EQ("", err.str());
820}
821
822TEST_F(ListTest, AllColumnsWithCmd) {
823 // clang-format off
824 const std::string expected =
825 "[fake description 0]\n"
826 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
827 "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"
828 "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"
829 "\n"
830 "[fake description 1]\n"
831 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
832 "a.h.foo3@3.0::IFoo/3 passthrough N/A 32 N/A ? X N/A command_line_4;command_line_6\n"
833 "a.h.foo4@4.0::IFoo/4 passthrough N/A 32 N/A ? X N/A command_line_5;command_line_7\n"
834 "\n"
835 "[fake description 2]\n"
836 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
837 "a.h.foo5@5.0::IFoo/5 passthrough N/A 32 N/A ? X N/A command_line_6;command_line_8\n"
838 "a.h.foo6@6.0::IFoo/6 passthrough N/A 32 N/A ? X N/A command_line_7;command_line_9\n"
839 "\n";
840 // clang-format on
841
842 optind = 1; // mimic Lshal::parseArg()
843 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"})));
844 EXPECT_EQ(expected, out.str());
845 EXPECT_EQ("", err.str());
846}
847
848TEST_F(ListTest, AllSections) {
849 optind = 1; // mimic Lshal::parseArg()
850 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"})));
851 using HalTypeBase = std::underlying_type_t<HalType>;
852 for (HalTypeBase i = 0; i < static_cast<HalTypeBase>(HalType::LAST); ++i) {
853 EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]"));
854 }
855 EXPECT_THAT(out.str(),
856 Not(HasSubstr("[fake description " +
857 std::to_string(static_cast<HalTypeBase>(HalType::LAST)) + "]")));
858 EXPECT_EQ("", err.str());
859}
860
Yifan Hong6884b872020-07-09 16:38:18 -0700861// Fake service returned by mocked IServiceManager::get for DumpDebug.
862// The interfaceChain and getHashChain functions returns
863// foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
864class InheritingService : public IBase {
865public:
866 explicit InheritingService(pid_t id) : mId(id) {}
867 android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
868 cb(getInterfaceName(mId));
869 return hardware::Void();
870 }
871 android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
872 std::vector<hidl_string> ret;
873 for (auto i = mId; i > 0; --i) {
874 ret.push_back(getInterfaceName(i));
875 }
876 ret.push_back(IBase::descriptor);
877 cb(ret);
878 return hardware::Void();
879 }
880 android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
881 std::vector<hidl_hash> ret;
882 for (auto i = mId; i > 0; --i) {
883 ret.push_back(getHashFromId(i));
884 }
885 ret.push_back(getHashFromId(0xff));
886 cb(ret);
887 return hardware::Void();
888 }
889 android::hardware::Return<void> debug(const hidl_handle& hh,
890 const hidl_vec<hidl_string>&) override {
891 const native_handle_t* handle = hh.getNativeHandle();
892 if (handle->numFds < 1) {
893 return Void();
894 }
895 int fd = handle->data[0];
896 std::string content = "debug info for ";
897 content += getInterfaceName(mId);
898 ssize_t written = write(fd, content.c_str(), content.size());
899 if (written != (ssize_t)content.size()) {
900 LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
901 << content.size() << " bytes, errno = " << errno;
902 }
903 return Void();
904 }
905
906private:
907 pid_t mId;
908};
909
910TEST_F(ListTest, DumpDebug) {
911 size_t inheritanceLevel = 3;
912 sp<IBase> service = new InheritingService(inheritanceLevel);
913
914 EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
915 std::vector<hidl_string> ret;
916 for (auto i = 1; i <= inheritanceLevel; ++i) {
917 ret.push_back(getInterfaceName(i) + "/default");
918 }
919 cb(ret);
920 return hardware::Void();
921 }));
922 EXPECT_CALL(*serviceManager, get(_, _))
923 .WillRepeatedly(
924 Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
925 int id = getIdFromInstanceName(instance);
926 if (id > inheritanceLevel) return nullptr;
927 return sp<IBase>(service);
928 }));
929
930 const std::string expected = "[fake description 0]\n"
931 "Interface\n"
932 "a.h.foo1@1.0::IFoo/default\n"
933 "[See a.h.foo3@3.0::IFoo/default]\n"
934 "a.h.foo2@2.0::IFoo/default\n"
935 "[See a.h.foo3@3.0::IFoo/default]\n"
936 "a.h.foo3@3.0::IFoo/default\n"
937 "debug info for a.h.foo3@3.0::IFoo\n"
938 "\n";
939
940 optind = 1; // mimic Lshal::parseArg()
941 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
942 EXPECT_EQ(expected, out.str());
943 EXPECT_EQ("", err.str());
944}
945
Yifan Hong13ba0a92018-06-25 16:15:56 -0700946class ListVintfTest : public ListTest {
947public:
948 virtual void SetUp() override {
949 ListTest::SetUp();
950 const std::string mockManifestXml =
951 "<manifest version=\"1.0\" type=\"device\">\n"
952 " <hal format=\"hidl\">\n"
953 " <name>a.h.foo1</name>\n"
954 " <transport>hwbinder</transport>\n"
955 " <fqname>@1.0::IFoo/1</fqname>\n"
956 " </hal>\n"
957 " <hal format=\"hidl\">\n"
958 " <name>a.h.bar1</name>\n"
959 " <transport>hwbinder</transport>\n"
960 " <fqname>@1.0::IBar/1</fqname>\n"
961 " </hal>\n"
962 " <hal format=\"hidl\">\n"
963 " <name>a.h.bar2</name>\n"
964 " <transport arch=\"32+64\">passthrough</transport>\n"
965 " <fqname>@2.0::IBar/2</fqname>\n"
966 " </hal>\n"
967 "</manifest>";
968 auto manifest = std::make_shared<HalManifest>();
969 EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
970 EXPECT_CALL(*mockList, getDeviceManifest())
971 .Times(AnyNumber())
972 .WillRepeatedly(Return(manifest));
973 }
974};
975
976TEST_F(ListVintfTest, ManifestHals) {
977 optind = 1; // mimic Lshal::parseArg()
978 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
979 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
980 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
981 EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder ?"));
982 EXPECT_EQ("", err.str());
983}
984
Yifan Hong3212f172018-06-28 12:39:50 -0700985TEST_F(ListVintfTest, Lazy) {
986 optind = 1; // mimic Lshal::parseArg()
987 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
988 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
989 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
990 EXPECT_EQ("", err.str());
991}
992
993TEST_F(ListVintfTest, NoLazy) {
994 optind = 1; // mimic Lshal::parseArg()
995 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
996 EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
997 EXPECT_EQ("", err.str());
998}
999
Yifan Honga8bedc62017-09-08 18:00:31 -07001000class HelpTest : public ::testing::Test {
1001public:
1002 void SetUp() override {
1003 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
1004 new MockServiceManager() /* passthruManager */);
1005 }
1006
1007 std::stringstream err;
1008 std::stringstream out;
1009 std::unique_ptr<Lshal> lshal;
1010};
1011
1012TEST_F(HelpTest, GlobalUsage) {
1013 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
1014 std::string errStr = err.str();
1015 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
1016 << "`lshal --help` does not contain global usage";
1017 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
1018 << "`lshal --help` does not contain usage for 'list' command";
1019 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
1020 << "`lshal --help` does not contain usage for 'debug' command";
1021 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
1022 << "`lshal --help` does not contain usage for 'help' command";
1023
1024 err.str("");
1025 (void)callMain(lshal, {"lshal", "help"}); // ignore return
1026 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
1027
1028 err.str("");
1029 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
1030 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1031 EXPECT_THAT(err.str(), EndsWith(errStr))
1032 << "`lshal --unknown-option` should have the same output as `lshal --help`";
1033 EXPECT_EQ("", out.str());
1034}
1035
1036TEST_F(HelpTest, UnknownOptionList1) {
1037 (void)callMain(lshal, {"lshal", "help", "list"});
1038 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1039 << "`lshal help list` does not contain usage for 'list' command";
1040}
1041
1042TEST_F(HelpTest, UnknownOptionList2) {
1043 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
1044 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1045 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1046 << "`lshal list --unknown-option` does not contain usage for 'list' command";
1047 EXPECT_EQ("", out.str());
1048}
1049
1050TEST_F(HelpTest, UnknownOptionHelp1) {
1051 (void)callMain(lshal, {"lshal", "help", "help"});
1052 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1053 << "`lshal help help` does not contain usage for 'help' command";
1054}
1055
1056TEST_F(HelpTest, UnknownOptionHelp2) {
1057 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
1058 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1059 << "`lshal help --unknown-option` does not contain usage for 'help' command";
1060 EXPECT_EQ("", out.str());
1061}
1062
Yifan Hong9881df92017-05-10 14:33:05 -07001063} // namespace lshal
1064} // namespace android
1065
1066int main(int argc, char **argv) {
1067 ::testing::InitGoogleMock(&argc, argv);
1068 return RUN_ALL_TESTS();
1069}