blob: cba7c4bf2a52bbd045624228d834ce99762946ed [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
Yifan Hong44b63872021-09-21 17:47:48 -070025#include <android-base/parseint.h>
Yifan Hong5cceea82020-07-09 19:34:58 -070026#include <android/hardware/tests/inheritance/1.0/IChild.h>
Yifan Hong44b63872021-09-21 17:47:48 -070027#include <gmock/gmock.h>
28#include <gtest/gtest.h>
Yifan Hong9881df92017-05-10 14:33:05 -070029#include <hidl/HidlTransportSupport.h>
Yifan Hong8bf73162017-09-07 18:06:13 -070030#include <vintf/parse_xml.h>
Yifan Hong9881df92017-05-10 14:33:05 -070031
Yifan Hongb2a2ecb2017-09-07 15:08:22 -070032#include "ListCommand.h"
Yifan Hong9881df92017-05-10 14:33:05 -070033#include "Lshal.h"
34
35#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
36
37using namespace testing;
38
Yifan Hong8bf73162017-09-07 18:06:13 -070039using ::android::hidl::base::V1_0::DebugInfo;
Yifan Hong9881df92017-05-10 14:33:05 -070040using ::android::hidl::base::V1_0::IBase;
41using ::android::hidl::manager::V1_0::IServiceManager;
42using ::android::hidl::manager::V1_0::IServiceNotification;
Yifan Hongfee209d2017-09-14 18:23:38 -070043using ::android::hardware::hidl_array;
Yifan Hong9881df92017-05-10 14:33:05 -070044using ::android::hardware::hidl_death_recipient;
45using ::android::hardware::hidl_handle;
46using ::android::hardware::hidl_string;
47using ::android::hardware::hidl_vec;
Yifan Hong5cceea82020-07-09 19:34:58 -070048using ::android::hardware::Void;
Yifan Hong0ad64f52018-05-25 15:29:17 -070049using android::vintf::Arch;
Yifan Hongbdf44f82018-05-25 14:20:00 -070050using android::vintf::CompatibilityMatrix;
Yifan Hongbdf44f82018-05-25 14:20:00 -070051using android::vintf::HalManifest;
Yifan Hong8304e412018-05-25 15:05:36 -070052using android::vintf::Transport;
Yifan Hongbdf44f82018-05-25 14:20:00 -070053using android::vintf::VintfObject;
Yifan Hong9881df92017-05-10 14:33:05 -070054
Yifan Hong8bf73162017-09-07 18:06:13 -070055using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
56
Yifan Hongfee209d2017-09-14 18:23:38 -070057using hidl_hash = hidl_array<uint8_t, 32>;
58
Yifan Hong9881df92017-05-10 14:33:05 -070059namespace android {
60namespace hardware {
61namespace tests {
Yifan Hong5cceea82020-07-09 19:34:58 -070062namespace inheritance {
Yifan Hong9881df92017-05-10 14:33:05 -070063namespace V1_0 {
64namespace implementation {
Yifan Hong5cceea82020-07-09 19:34:58 -070065struct Child : android::hardware::tests::inheritance::V1_0::IChild {
66 ::android::hardware::Return<void> doChild() override { return Void(); }
67 ::android::hardware::Return<void> doParent() override { return Void(); }
68 ::android::hardware::Return<void> doGrandparent() override { return Void(); }
69
Yifan Hong9881df92017-05-10 14:33:05 -070070 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
71 const native_handle_t *handle = hh.getNativeHandle();
72 if (handle->numFds < 1) {
73 return Void();
74 }
75 int fd = handle->data[0];
76 std::string content{descriptor};
77 for (const auto &option : options) {
78 content += "\n";
79 content += option.c_str();
80 }
Yifan Hong44b63872021-09-21 17:47:48 -070081 if (options.size() > 0) {
82 uint64_t len;
83 if (android::base::ParseUint(options[0], &len)) {
84 content += "\n";
85 content += std::string(len, 'X');
86 }
87 }
Yifan Hong9881df92017-05-10 14:33:05 -070088 ssize_t written = write(fd, content.c_str(), content.size());
89 if (written != (ssize_t)content.size()) {
Yifan Hong5cceea82020-07-09 19:34:58 -070090 LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
Yifan Hong9881df92017-05-10 14:33:05 -070091 << content.size() << " bytes, errno = " << errno;
92 }
93 return Void();
94 }
95};
96
97} // namespace implementation
98} // namespace V1_0
Yifan Hong5cceea82020-07-09 19:34:58 -070099} // namespace inheritance
Yifan Hong9881df92017-05-10 14:33:05 -0700100} // namespace tests
101} // namespace hardware
102
103namespace lshal {
104
Yifan Hong9881df92017-05-10 14:33:05 -0700105class MockServiceManager : public IServiceManager {
106public:
107 template<typename T>
108 using R = ::android::hardware::Return<T>;
109 using String = const hidl_string&;
110 ~MockServiceManager() = default;
111
112#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
113
114 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
115 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
116 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
117 MOCK_METHOD_CB(list);
118 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
119 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
120 MOCK_METHOD_CB(debugDump);
121 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
122 MOCK_METHOD_CB(interfaceChain);
123 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
124 MOCK_METHOD_CB(interfaceDescriptor);
125 MOCK_METHOD_CB(getHashChain);
126 MOCK_METHOD0(setHalInstrumentation, R<void>());
127 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
128 MOCK_METHOD0(ping, R<void>());
129 MOCK_METHOD_CB(getDebugInfo);
130 MOCK_METHOD0(notifySyspropsChanged, R<void>());
131 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
132
133};
134
Yifan Hongbf20a262017-09-07 11:10:58 -0700135class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700136public:
137 void SetUp() override {
Yifan Hong5cceea82020-07-09 19:34:58 -0700138 using ::android::hardware::tests::inheritance::V1_0::IChild;
139 using ::android::hardware::tests::inheritance::V1_0::IParent;
140 using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
141 using ::android::hardware::tests::inheritance::V1_0::implementation::Child;
Yifan Hong9881df92017-05-10 14:33:05 -0700142
143 err.str("");
144 out.str("");
145 serviceManager = new testing::NiceMock<MockServiceManager>();
Yifan Hong5cceea82020-07-09 19:34:58 -0700146 ON_CALL(*serviceManager, get(_, _))
147 .WillByDefault(
148 Invoke([](const auto& iface,
149 const auto& inst) -> ::android::hardware::Return<sp<IBase>> {
150 if (inst != "default") return nullptr;
151 if (iface == IChild::descriptor || iface == IParent::descriptor ||
152 iface == IGrandparent::descriptor)
153 return new Child();
154 return nullptr;
155 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700156
157 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700158 }
159 void TearDown() override {}
160
161 std::stringstream err;
162 std::stringstream out;
163 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700164
165 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700166};
167
Yifan Hongbf20a262017-09-07 11:10:58 -0700168static Arg createArg(const std::vector<const char*>& args) {
169 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
170}
171
172template<typename T>
173static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
174 return lshal->main(createArg(args));
175}
176
177TEST_F(DebugTest, Debug) {
178 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700179 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "foo", "bar"
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\nfoo\nbar"));
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, Debug2) {
186 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong5cceea82020-07-09 19:34:58 -0700187 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700188 }));
Yifan Hong5cceea82020-07-09 19:34:58 -0700189 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nbaz\nquux"));
Yifan Hong9881df92017-05-10 14:33:05 -0700190 EXPECT_THAT(err.str(), IsEmpty());
191}
192
Yifan Hongbf20a262017-09-07 11:10:58 -0700193TEST_F(DebugTest, Debug3) {
194 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700195 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700196 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700197 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
198}
199
Yifan Hong44b63872021-09-21 17:47:48 -0700200TEST_F(DebugTest, DebugLarge) {
201 EXPECT_EQ(0u, callMain(lshal, {
202 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "10000"
203 }));
204 EXPECT_THAT(out.str(),
205 StrEq("android.hardware.tests.inheritance@1.0::IChild\n10000\n" +
206 std::string(10000, 'X')));
207 EXPECT_THAT(err.str(), IsEmpty());
208}
209
Yifan Hong5cceea82020-07-09 19:34:58 -0700210TEST_F(DebugTest, DebugParent) {
211 EXPECT_EQ(0u, callMain(lshal, {
212 "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
213 }));
214 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\ncalling parent"));
215 EXPECT_THAT(err.str(), IsEmpty());
216}
217
218TEST_F(DebugTest, DebugParentExclude) {
219 EXPECT_EQ(0u, callMain(lshal, {
220 "lshal", "debug", "-E", "android.hardware.tests.inheritance@1.0::IParent", "excluding"
221 }));
222 EXPECT_THAT(out.str(), IsEmpty());
223 EXPECT_THAT(err.str(), IsEmpty());
224}
225
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700226class MockLshal : public Lshal {
227public:
228 MockLshal() {}
229 ~MockLshal() = default;
230 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
231 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
232};
233
234// expose protected fields and methods for ListCommand
235class MockListCommand : public ListCommand {
236public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800237 explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700238
Yifan Honga8bedc62017-09-08 18:00:31 -0700239 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
240 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700241 void forEachTable(const std::function<void(Table &)> &f) {
242 return ListCommand::forEachTable(f);
243 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700244 void forEachTable(const std::function<void(const Table &)> &f) const {
245 return ListCommand::forEachTable(f);
246 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700247 Status fetch() { return ListCommand::fetch(); }
248 void dumpVintf(const NullableOStream<std::ostream>& out) {
249 return ListCommand::dumpVintf(out);
250 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700251 void internalPostprocess() { ListCommand::postprocess(); }
Devin Moorec03e3aa2020-12-11 15:11:17 -0800252 const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
Yifan Hong1243dde2017-09-14 17:49:30 -0700253 return ListCommand::getPidInfoCached(serverPid);
254 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700255
Yifan Hong93b8bff2017-09-14 16:02:52 -0700256 MOCK_METHOD0(postprocess, void());
Devin Moorec03e3aa2020-12-11 15:11:17 -0800257 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
Yifan Hong8bf73162017-09-07 18:06:13 -0700258 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongf31aa052018-02-02 15:17:51 -0800259 MOCK_METHOD1(getPartition, Partition(pid_t));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700260
261 MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
262 MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
263 MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
264 MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700265};
266
267class ListParseArgsTest : public ::testing::Test {
268public:
269 void SetUp() override {
270 mockLshal = std::make_unique<NiceMock<MockLshal>>();
271 mockList = std::make_unique<MockListCommand>(mockLshal.get());
Yifan Hongc4430912018-06-27 16:48:34 -0700272 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700273 // ListCommand::parseArgs should parse arguments from the second element
274 optind = 1;
275 }
276 std::unique_ptr<MockLshal> mockLshal;
277 std::unique_ptr<MockListCommand> mockList;
Yifan Hongc4430912018-06-27 16:48:34 -0700278 std::stringstream err;
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700279};
280
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700281TEST_F(ListParseArgsTest, Args) {
282 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
283 mockList->forEachTable([](const Table& table) {
284 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
285 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
286 table.getSelectedColumns());
287 });
Yifan Hongc4430912018-06-27 16:48:34 -0700288 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700289}
290
291TEST_F(ListParseArgsTest, Cmds) {
292 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
293 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700294 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
295 << "should not print server PID with -m";
296 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
297 << "should not print client PIDs with -m";
298 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
299 << "should print server cmd with -m";
300 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
301 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700302 });
Yifan Hongc4430912018-06-27 16:48:34 -0700303 EXPECT_EQ("", err.str());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700304}
305
306TEST_F(ListParseArgsTest, DebugAndNeat) {
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700307 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
Yifan Hongc4430912018-06-27 16:48:34 -0700308 EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700309}
310
Yifan Hong8bf73162017-09-07 18:06:13 -0700311/// Fetch Test
312
313// A set of deterministic functions to generate fake debug infos.
314static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
315static std::vector<pid_t> getClients(pid_t serverId) {
316 return {serverId + 1, serverId + 3};
317}
Devin Moorec03e3aa2020-12-11 15:11:17 -0800318static BinderPidInfo getPidInfoFromId(pid_t serverId) {
319 BinderPidInfo info;
Yifan Hong8bf73162017-09-07 18:06:13 -0700320 info.refPids[getPtr(serverId)] = getClients(serverId);
321 info.threadUsage = 10 + serverId;
322 info.threadCount = 20 + serverId;
323 return info;
324}
325static std::string getInterfaceName(pid_t serverId) {
326 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
327}
328static std::string getInstanceName(pid_t serverId) {
329 return std::to_string(serverId);
330}
331static pid_t getIdFromInstanceName(const hidl_string& instance) {
332 return atoi(instance.c_str());
333}
334static std::string getFqInstanceName(pid_t serverId) {
335 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
336}
337static std::string getCmdlineFromId(pid_t serverId) {
338 if (serverId == NO_PID) return "";
339 return "command_line_" + std::to_string(serverId);
340}
Yifan Hongfee209d2017-09-14 18:23:38 -0700341static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
342static hidl_hash getHashFromId(pid_t serverId) {
343 hidl_hash hash;
344 bool isReleased = getIsReleasedFromId(serverId);
345 for (size_t i = 0; i < hash.size(); ++i) {
346 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
347 }
348 return hash;
349}
Yifan Hong8bf73162017-09-07 18:06:13 -0700350
351// Fake service returned by mocked IServiceManager::get.
352class TestService : public IBase {
353public:
Chih-Hung Hsieh45e31c72018-12-20 15:47:01 -0800354 explicit TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700355 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700356 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
357 return hardware::Void();
358 }
359 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
360 cb({getInterfaceName(mId), IBase::descriptor});
361 return hardware::Void();
362 }
363 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
364 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700365 return hardware::Void();
366 }
367private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700368 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700369};
370
371class ListTest : public ::testing::Test {
372public:
Yifan Hong13ba0a92018-06-25 16:15:56 -0700373 virtual void SetUp() override {
Yifan Hong8bf73162017-09-07 18:06:13 -0700374 initMockServiceManager();
375 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
376 initMockList();
377 }
378
379 void initMockList() {
380 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
381 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
Devin Moorec03e3aa2020-12-11 15:11:17 -0800382 [](pid_t serverPid, BinderPidInfo* info) {
Yifan Hong8bf73162017-09-07 18:06:13 -0700383 *info = getPidInfoFromId(serverPid);
384 return true;
385 }));
386 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700387 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
388 mockList->internalPostprocess();
389 size_t i = 0;
390 mockList->forEachTable([&](Table& table) {
391 table.setDescription("[fake description " + std::to_string(i++) + "]");
392 });
393 }));
Yifan Hongf31aa052018-02-02 15:17:51 -0800394 ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700395
396 ON_CALL(*mockList, getDeviceManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700397 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700398 ON_CALL(*mockList, getDeviceMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700399 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700400 ON_CALL(*mockList, getFrameworkManifest())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700401 .WillByDefault(Return(std::make_shared<HalManifest>()));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700402 ON_CALL(*mockList, getFrameworkMatrix())
Yifan Hong13ba0a92018-06-25 16:15:56 -0700403 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
Yifan Hong8bf73162017-09-07 18:06:13 -0700404 }
405
406 void initMockServiceManager() {
407 serviceManager = new testing::NiceMock<MockServiceManager>();
408 passthruManager = new testing::NiceMock<MockServiceManager>();
409 using A = DebugInfo::Architecture;
410 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
411 [] (IServiceManager::list_cb cb) {
412 cb({ getFqInstanceName(1), getFqInstanceName(2) });
413 return hardware::Void();
414 }));
415
416 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
417 [&](const hidl_string&, const hidl_string& instance) {
418 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700419 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700420 }));
421
422 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
423 [] (IServiceManager::debugDump_cb cb) {
424 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
425 getClients(3), A::IS_32BIT},
426 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
427 getClients(4), A::IS_32BIT}});
428 return hardware::Void();
429 }));
430
431 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
432 [] (IServiceManager::debugDump_cb cb) {
433 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
434 getClients(5), A::IS_32BIT},
435 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
436 getClients(6), A::IS_32BIT}});
437 return hardware::Void();
438 }));
439 }
440
441 std::stringstream err;
442 std::stringstream out;
443 std::unique_ptr<Lshal> lshal;
444 std::unique_ptr<MockListCommand> mockList;
445 sp<MockServiceManager> serviceManager;
446 sp<MockServiceManager> passthruManager;
447};
448
Yifan Hong1243dde2017-09-14 17:49:30 -0700449TEST_F(ListTest, GetPidInfoCached) {
450 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
451
452 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
453 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
454}
455
Yifan Hong8bf73162017-09-07 18:06:13 -0700456TEST_F(ListTest, Fetch) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700457 optind = 1; // mimic Lshal::parseArg()
458 ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
459 ASSERT_EQ(0u, mockList->fetch());
Yifan Hong0ad64f52018-05-25 15:29:17 -0700460 vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
461 vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
462 std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
463 passthrough, passthrough, passthrough}};
Yifan Hong13ba0a92018-06-25 16:15:56 -0700464 int i = 0;
Yifan Hong8bf73162017-09-07 18:06:13 -0700465 mockList->forEachTable([&](const Table& table) {
Yifan Hong8bf73162017-09-07 18:06:13 -0700466 for (const auto& entry : table) {
Yifan Hong13ba0a92018-06-25 16:15:56 -0700467 if (i >= transportArchs.size()) {
468 break;
469 }
470
471 int id = i + 1;
472 auto transport = transportArchs.at(i).transport;
Yifan Hong8bf73162017-09-07 18:06:13 -0700473 TableEntry expected{
474 .interfaceName = getFqInstanceName(id),
475 .transport = transport,
Yifan Hong8304e412018-05-25 15:05:36 -0700476 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
477 .threadUsage =
478 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
479 .threadCount =
480 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
Yifan Hong8bf73162017-09-07 18:06:13 -0700481 .serverCmdline = {},
Yifan Hong8304e412018-05-25 15:05:36 -0700482 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
Yifan Hong8bf73162017-09-07 18:06:13 -0700483 .clientPids = getClients(id),
484 .clientCmdlines = {},
Yifan Hong13ba0a92018-06-25 16:15:56 -0700485 .arch = transportArchs.at(i).arch,
Yifan Hong8bf73162017-09-07 18:06:13 -0700486 };
487 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
488
Yifan Hong13ba0a92018-06-25 16:15:56 -0700489 ++i;
Yifan Hong8bf73162017-09-07 18:06:13 -0700490 }
491 });
492
Yifan Hong13ba0a92018-06-25 16:15:56 -0700493 EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
494
Yifan Hong8bf73162017-09-07 18:06:13 -0700495}
496
497TEST_F(ListTest, DumpVintf) {
Yifan Hong29b35b62020-10-14 21:17:07 -0700498 const std::string expected = " <hal format=\"hidl\">\n"
Yifan Hongb2d096a2018-05-01 15:25:23 -0700499 " <name>a.h.foo1</name>\n"
500 " <transport>hwbinder</transport>\n"
501 " <fqname>@1.0::IFoo/1</fqname>\n"
502 " </hal>\n"
503 " <hal format=\"hidl\">\n"
504 " <name>a.h.foo2</name>\n"
505 " <transport>hwbinder</transport>\n"
506 " <fqname>@2.0::IFoo/2</fqname>\n"
507 " </hal>\n"
508 " <hal format=\"hidl\">\n"
509 " <name>a.h.foo3</name>\n"
510 " <transport arch=\"32\">passthrough</transport>\n"
511 " <fqname>@3.0::IFoo/3</fqname>\n"
512 " </hal>\n"
513 " <hal format=\"hidl\">\n"
514 " <name>a.h.foo4</name>\n"
515 " <transport arch=\"32\">passthrough</transport>\n"
516 " <fqname>@4.0::IFoo/4</fqname>\n"
Yifan Hong29b35b62020-10-14 21:17:07 -0700517 " </hal>\n";
Yifan Hong8bf73162017-09-07 18:06:13 -0700518
519 optind = 1; // mimic Lshal::parseArg()
520 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
Yifan Hongb2d096a2018-05-01 15:25:23 -0700521 auto output = out.str();
522 EXPECT_THAT(output, HasSubstr(expected));
523 EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
524 EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
Yifan Hong8bf73162017-09-07 18:06:13 -0700525 EXPECT_EQ("", err.str());
526
Yifan Hong24d03042021-04-05 18:34:59 -0700527 std::string error;
Yifan Hong8bf73162017-09-07 18:06:13 -0700528 vintf::HalManifest m;
Yifan Honga96f87f2021-04-16 18:59:27 -0700529 EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
Yifan Hong24d03042021-04-05 18:34:59 -0700530 << "--init-vintf does not emit valid HAL manifest: " << error;
Yifan Hong8bf73162017-09-07 18:06:13 -0700531}
532
Yifan Hongfee209d2017-09-14 18:23:38 -0700533// test default columns
534TEST_F(ListTest, DumpDefault) {
535 const std::string expected =
536 "[fake description 0]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700537 "VINTF R Interface Thread Use Server Clients\n"
538 "X N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
539 "X Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700540 "\n"
541 "[fake description 1]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700542 "VINTF R Interface Thread Use Server Clients\n"
543 "X ? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
544 "X ? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700545 "\n"
546 "[fake description 2]\n"
Steven Morelandeae1a0b2019-06-25 13:01:49 -0700547 "VINTF R Interface Thread Use Server Clients\n"
548 "X ? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
549 "X ? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700550 "\n";
551
552 optind = 1; // mimic Lshal::parseArg()
553 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
554 EXPECT_EQ(expected, out.str());
555 EXPECT_EQ("", err.str());
556}
557
558TEST_F(ListTest, DumpHash) {
559 const std::string expected =
560 "[fake description 0]\n"
561 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700562 "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700563 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
564 "\n"
565 "[fake description 1]\n"
566 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700567 "a.h.foo3@3.0::IFoo/3 ? \n"
568 "a.h.foo4@4.0::IFoo/4 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700569 "\n"
570 "[fake description 2]\n"
571 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700572 "a.h.foo5@5.0::IFoo/5 ? \n"
573 "a.h.foo6@6.0::IFoo/6 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700574 "\n";
575
576 optind = 1; // mimic Lshal::parseArg()
577 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
578 EXPECT_EQ(expected, out.str());
579 EXPECT_EQ("", err.str());
580}
581
Yifan Hong8bf73162017-09-07 18:06:13 -0700582TEST_F(ListTest, Dump) {
583 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700584 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700585 "Interface Transport Arch Thread Use Server PTR Clients\n"
586 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
587 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
588 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700589 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700590 "Interface Transport Arch Thread Use Server PTR Clients\n"
591 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
592 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
593 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700594 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700595 "Interface Transport Arch Thread Use Server PTR Clients\n"
596 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
597 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
598 "\n";
599
600 optind = 1; // mimic Lshal::parseArg()
601 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
602 EXPECT_EQ(expected, out.str());
603 EXPECT_EQ("", err.str());
604}
605
606TEST_F(ListTest, DumpCmdline) {
607 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700608 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700609 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
610 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
611 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
612 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700613 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700614 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
615 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
616 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
617 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700618 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700619 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
620 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
621 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
622 "\n";
623
624 optind = 1; // mimic Lshal::parseArg()
625 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
626 EXPECT_EQ(expected, out.str());
627 EXPECT_EQ("", err.str());
628}
629
630TEST_F(ListTest, DumpNeat) {
631 const std::string expected =
632 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
633 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
634 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
635 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
636 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
637 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
638
639 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700640 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700641 EXPECT_EQ(expected, out.str());
642 EXPECT_EQ("", err.str());
643}
Yifan Honga8bedc62017-09-08 18:00:31 -0700644
Nirav Atrecce988d2018-05-16 11:14:46 -0700645TEST_F(ListTest, DumpSingleHalType) {
646 const std::string expected =
647 "[fake description 0]\n"
648 "Interface Transport Arch Thread Use Server PTR Clients\n"
649 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
650 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
651 "\n";
652
653 optind = 1; // mimic Lshal::parseArg()
654 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
655 EXPECT_EQ(expected, out.str());
656 EXPECT_EQ("", err.str());
657}
658
659TEST_F(ListTest, DumpReorderedHalTypes) {
660 const std::string expected =
661 "[fake description 0]\n"
662 "Interface Transport Arch Thread Use Server PTR Clients\n"
663 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
664 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
665 "\n"
666 "[fake description 1]\n"
667 "Interface Transport Arch Thread Use Server PTR Clients\n"
668 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
669 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
670 "\n"
671 "[fake description 2]\n"
672 "Interface Transport Arch Thread Use Server PTR Clients\n"
673 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
674 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
675 "\n";
676
677 optind = 1; // mimic Lshal::parseArg()
678 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
679 "--types=passthrough_libs", "--types=binderized"})));
680 EXPECT_EQ(expected, out.str());
681 EXPECT_EQ("", err.str());
682}
683
684TEST_F(ListTest, DumpAbbreviatedHalTypes) {
685 const std::string expected =
686 "[fake description 0]\n"
687 "Interface Transport Arch Thread Use Server PTR Clients\n"
688 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
689 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
690 "\n"
691 "[fake description 1]\n"
692 "Interface Transport Arch Thread Use Server PTR Clients\n"
693 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
694 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
695 "\n";
696
697 optind = 1; // mimic Lshal::parseArg()
698 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
699 EXPECT_EQ(expected, out.str());
700 EXPECT_EQ("", err.str());
701}
702
703TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
704 const std::string expected =
705 "[fake description 0]\n"
706 "Interface Transport Arch Thread Use Server PTR Clients\n"
707 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
708 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
709 "\n"
710 "[fake description 1]\n"
711 "Interface Transport Arch Thread Use Server PTR Clients\n"
712 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
713 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
714 "\n";
715
716 optind = 1; // mimic Lshal::parseArg()
717 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
718 "--types=passthrough_libs,passthrough_clients"})));
719 EXPECT_EQ(expected, out.str());
720 EXPECT_EQ("", err.str());
721}
722
723TEST_F(ListTest, UnknownHalType) {
724 optind = 1; // mimic Lshal::parseArg()
Yifan Hong30528a22020-08-07 18:24:06 -0700725 EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"})));
726 EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r"));
Nirav Atrecce988d2018-05-16 11:14:46 -0700727}
728
Yifan Hongbdf44f82018-05-25 14:20:00 -0700729TEST_F(ListTest, Vintf) {
730 std::string deviceManifestXml =
731 "<manifest version=\"1.0\" type=\"device\">\n"
732 " <hal>\n"
733 " <name>a.h.foo1</name>\n"
734 " <transport>hwbinder</transport>\n"
735 " <fqname>@1.0::IFoo/1</fqname>\n"
736 " </hal>\n"
737 " <hal>\n"
738 " <name>a.h.foo3</name>\n"
739 " <transport arch=\"32+64\">passthrough</transport>\n"
740 " <fqname>@3.0::IFoo/3</fqname>\n"
741 " </hal>\n"
742 "</manifest>\n";
743 std::string frameworkManifestXml =
744 "<manifest version=\"1.0\" type=\"framework\">\n"
745 " <hal>\n"
746 " <name>a.h.foo5</name>\n"
747 " <transport arch=\"32\">passthrough</transport>\n"
748 " <fqname>@5.0::IFoo/5</fqname>\n"
749 " </hal>\n"
750 "</manifest>\n";
751 std::string deviceMatrixXml =
752 "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
753 " <hal>\n"
754 " <name>a.h.foo5</name>\n"
755 " <version>5.0</version>\n"
756 " <interface>\n"
757 " <name>IFoo</name>\n"
758 " <instance>5</instance>\n"
759 " </interface>\n"
760 " </hal>\n"
761 "</compatibility-matrix>\n";
762 std::string frameworkMatrixXml =
763 "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
764 " <hal>\n"
765 " <name>a.h.foo1</name>\n"
766 " <version>1.0</version>\n"
767 " <interface>\n"
768 " <name>IFoo</name>\n"
769 " <instance>1</instance>\n"
770 " </interface>\n"
771 " </hal>\n"
772 " <hal>\n"
773 " <name>a.h.foo3</name>\n"
774 " <version>3.0</version>\n"
775 " <interface>\n"
776 " <name>IFoo</name>\n"
777 " <instance>3</instance>\n"
778 " </interface>\n"
779 " </hal>\n"
780 "</compatibility-matrix>\n";
781
782 std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
783 "X a.h.foo2@2.0::IFoo/2\n"
784 "DM,FC a.h.foo3@3.0::IFoo/3\n"
785 "X a.h.foo4@4.0::IFoo/4\n"
786 "DC,FM a.h.foo5@5.0::IFoo/5\n"
787 "X a.h.foo6@6.0::IFoo/6\n";
788
789 auto deviceManifest = std::make_shared<HalManifest>();
790 auto frameworkManifest = std::make_shared<HalManifest>();
791 auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
792 auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
793
Yifan Honga96f87f2021-04-16 18:59:27 -0700794 ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
795 ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
796 ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
797 ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700798
799 ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
800 ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
801 ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
802 ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
803
804 optind = 1; // mimic Lshal::parseArg()
805 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
806 EXPECT_THAT(out.str(), HasSubstr(expected));
807 EXPECT_EQ("", err.str());
808}
809
Yifan Hong30528a22020-08-07 18:24:06 -0700810TEST_F(ListTest, AllColumns) {
811 // clang-format off
812 const std::string expected =
813 "[fake description 0]\n"
814 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
815 "a.h.foo1@1.0::IFoo/1 hwbinder 1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive 2 4\n"
816 "a.h.foo2@2.0::IFoo/2 hwbinder 2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive 3 5\n"
817 "\n"
818 "[fake description 1]\n"
819 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
820 "a.h.foo3@3.0::IFoo/3 passthrough N/A N/A 32 N/A ? X N/A 4 6\n"
821 "a.h.foo4@4.0::IFoo/4 passthrough N/A N/A 32 N/A ? X N/A 5 7\n"
822 "\n"
823 "[fake description 2]\n"
824 "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
825 "a.h.foo5@5.0::IFoo/5 passthrough N/A N/A 32 N/A ? X N/A 6 8\n"
826 "a.h.foo6@6.0::IFoo/6 passthrough N/A N/A 32 N/A ? X N/A 7 9\n"
827 "\n";
828 // clang-format on
829
830 optind = 1; // mimic Lshal::parseArg()
831 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"})));
832 EXPECT_EQ(expected, out.str());
833 EXPECT_EQ("", err.str());
834}
835
836TEST_F(ListTest, AllColumnsWithCmd) {
837 // clang-format off
838 const std::string expected =
839 "[fake description 0]\n"
840 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
841 "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"
842 "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"
843 "\n"
844 "[fake description 1]\n"
845 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
846 "a.h.foo3@3.0::IFoo/3 passthrough N/A 32 N/A ? X N/A command_line_4;command_line_6\n"
847 "a.h.foo4@4.0::IFoo/4 passthrough N/A 32 N/A ? X N/A command_line_5;command_line_7\n"
848 "\n"
849 "[fake description 2]\n"
850 "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
851 "a.h.foo5@5.0::IFoo/5 passthrough N/A 32 N/A ? X N/A command_line_6;command_line_8\n"
852 "a.h.foo6@6.0::IFoo/6 passthrough N/A 32 N/A ? X N/A command_line_7;command_line_9\n"
853 "\n";
854 // clang-format on
855
856 optind = 1; // mimic Lshal::parseArg()
857 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"})));
858 EXPECT_EQ(expected, out.str());
859 EXPECT_EQ("", err.str());
860}
861
862TEST_F(ListTest, AllSections) {
863 optind = 1; // mimic Lshal::parseArg()
864 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"})));
865 using HalTypeBase = std::underlying_type_t<HalType>;
866 for (HalTypeBase i = 0; i < static_cast<HalTypeBase>(HalType::LAST); ++i) {
867 EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]"));
868 }
869 EXPECT_THAT(out.str(),
870 Not(HasSubstr("[fake description " +
871 std::to_string(static_cast<HalTypeBase>(HalType::LAST)) + "]")));
872 EXPECT_EQ("", err.str());
873}
874
Yifan Hong6884b872020-07-09 16:38:18 -0700875// Fake service returned by mocked IServiceManager::get for DumpDebug.
876// The interfaceChain and getHashChain functions returns
877// foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
878class InheritingService : public IBase {
879public:
880 explicit InheritingService(pid_t id) : mId(id) {}
881 android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
882 cb(getInterfaceName(mId));
883 return hardware::Void();
884 }
885 android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
886 std::vector<hidl_string> ret;
887 for (auto i = mId; i > 0; --i) {
888 ret.push_back(getInterfaceName(i));
889 }
890 ret.push_back(IBase::descriptor);
891 cb(ret);
892 return hardware::Void();
893 }
894 android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
895 std::vector<hidl_hash> ret;
896 for (auto i = mId; i > 0; --i) {
897 ret.push_back(getHashFromId(i));
898 }
899 ret.push_back(getHashFromId(0xff));
900 cb(ret);
901 return hardware::Void();
902 }
903 android::hardware::Return<void> debug(const hidl_handle& hh,
904 const hidl_vec<hidl_string>&) override {
905 const native_handle_t* handle = hh.getNativeHandle();
906 if (handle->numFds < 1) {
907 return Void();
908 }
909 int fd = handle->data[0];
910 std::string content = "debug info for ";
911 content += getInterfaceName(mId);
912 ssize_t written = write(fd, content.c_str(), content.size());
913 if (written != (ssize_t)content.size()) {
914 LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
915 << content.size() << " bytes, errno = " << errno;
916 }
917 return Void();
918 }
919
920private:
921 pid_t mId;
922};
923
924TEST_F(ListTest, DumpDebug) {
925 size_t inheritanceLevel = 3;
926 sp<IBase> service = new InheritingService(inheritanceLevel);
927
928 EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
929 std::vector<hidl_string> ret;
930 for (auto i = 1; i <= inheritanceLevel; ++i) {
931 ret.push_back(getInterfaceName(i) + "/default");
932 }
933 cb(ret);
934 return hardware::Void();
935 }));
936 EXPECT_CALL(*serviceManager, get(_, _))
937 .WillRepeatedly(
938 Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
939 int id = getIdFromInstanceName(instance);
940 if (id > inheritanceLevel) return nullptr;
941 return sp<IBase>(service);
942 }));
943
944 const std::string expected = "[fake description 0]\n"
945 "Interface\n"
946 "a.h.foo1@1.0::IFoo/default\n"
947 "[See a.h.foo3@3.0::IFoo/default]\n"
948 "a.h.foo2@2.0::IFoo/default\n"
949 "[See a.h.foo3@3.0::IFoo/default]\n"
950 "a.h.foo3@3.0::IFoo/default\n"
951 "debug info for a.h.foo3@3.0::IFoo\n"
952 "\n";
953
954 optind = 1; // mimic Lshal::parseArg()
955 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
956 EXPECT_EQ(expected, out.str());
957 EXPECT_EQ("", err.str());
958}
959
Yifan Hong13ba0a92018-06-25 16:15:56 -0700960class ListVintfTest : public ListTest {
961public:
962 virtual void SetUp() override {
963 ListTest::SetUp();
964 const std::string mockManifestXml =
965 "<manifest version=\"1.0\" type=\"device\">\n"
966 " <hal format=\"hidl\">\n"
967 " <name>a.h.foo1</name>\n"
968 " <transport>hwbinder</transport>\n"
969 " <fqname>@1.0::IFoo/1</fqname>\n"
970 " </hal>\n"
971 " <hal format=\"hidl\">\n"
972 " <name>a.h.bar1</name>\n"
973 " <transport>hwbinder</transport>\n"
974 " <fqname>@1.0::IBar/1</fqname>\n"
975 " </hal>\n"
976 " <hal format=\"hidl\">\n"
977 " <name>a.h.bar2</name>\n"
978 " <transport arch=\"32+64\">passthrough</transport>\n"
979 " <fqname>@2.0::IBar/2</fqname>\n"
980 " </hal>\n"
981 "</manifest>";
982 auto manifest = std::make_shared<HalManifest>();
Yifan Honga96f87f2021-04-16 18:59:27 -0700983 EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
Yifan Hong13ba0a92018-06-25 16:15:56 -0700984 EXPECT_CALL(*mockList, getDeviceManifest())
985 .Times(AnyNumber())
986 .WillRepeatedly(Return(manifest));
987 }
988};
989
990TEST_F(ListVintfTest, ManifestHals) {
991 optind = 1; // mimic Lshal::parseArg()
992 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
993 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
994 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
995 EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder ?"));
996 EXPECT_EQ("", err.str());
997}
998
Yifan Hong3212f172018-06-28 12:39:50 -0700999TEST_F(ListVintfTest, Lazy) {
1000 optind = 1; // mimic Lshal::parseArg()
1001 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
1002 EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder ?"));
1003 EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
1004 EXPECT_EQ("", err.str());
1005}
1006
1007TEST_F(ListVintfTest, NoLazy) {
1008 optind = 1; // mimic Lshal::parseArg()
1009 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
1010 EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
1011 EXPECT_EQ("", err.str());
1012}
1013
Yifan Honga8bedc62017-09-08 18:00:31 -07001014class HelpTest : public ::testing::Test {
1015public:
1016 void SetUp() override {
1017 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
1018 new MockServiceManager() /* passthruManager */);
1019 }
1020
1021 std::stringstream err;
1022 std::stringstream out;
1023 std::unique_ptr<Lshal> lshal;
1024};
1025
1026TEST_F(HelpTest, GlobalUsage) {
1027 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
1028 std::string errStr = err.str();
1029 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
1030 << "`lshal --help` does not contain global usage";
1031 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
1032 << "`lshal --help` does not contain usage for 'list' command";
1033 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
1034 << "`lshal --help` does not contain usage for 'debug' command";
1035 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
1036 << "`lshal --help` does not contain usage for 'help' command";
1037
1038 err.str("");
1039 (void)callMain(lshal, {"lshal", "help"}); // ignore return
1040 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
1041
1042 err.str("");
1043 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
1044 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1045 EXPECT_THAT(err.str(), EndsWith(errStr))
1046 << "`lshal --unknown-option` should have the same output as `lshal --help`";
1047 EXPECT_EQ("", out.str());
1048}
1049
1050TEST_F(HelpTest, UnknownOptionList1) {
1051 (void)callMain(lshal, {"lshal", "help", "list"});
1052 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1053 << "`lshal help list` does not contain usage for 'list' command";
1054}
1055
1056TEST_F(HelpTest, UnknownOptionList2) {
1057 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
1058 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1059 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1060 << "`lshal list --unknown-option` does not contain usage for 'list' command";
1061 EXPECT_EQ("", out.str());
1062}
1063
1064TEST_F(HelpTest, UnknownOptionHelp1) {
1065 (void)callMain(lshal, {"lshal", "help", "help"});
1066 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1067 << "`lshal help help` does not contain usage for 'help' command";
1068}
1069
1070TEST_F(HelpTest, UnknownOptionHelp2) {
1071 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
1072 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1073 << "`lshal help --unknown-option` does not contain usage for 'help' command";
1074 EXPECT_EQ("", out.str());
1075}
1076
Yifan Hong9881df92017-05-10 14:33:05 -07001077} // namespace lshal
1078} // namespace android
1079
1080int main(int argc, char **argv) {
1081 ::testing::InitGoogleMock(&argc, argv);
1082 return RUN_ALL_TESTS();
1083}