using ::android::hidl::manager::V1_0::IServiceManager;
-Lshal::Lshal() {
+Lshal::Lshal()
+ : mOut(std::cout), mErr(std::cerr),
+ mServiceManager(::android::hardware::defaultServiceManager()),
+ mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+}
+
+Lshal::Lshal(std::ostream &out, std::ostream &err,
+ sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+ sp<hidl::manager::V1_0::IServiceManager> passthroughManager)
+ : mOut(out), mErr(err),
+ mServiceManager(serviceManager),
+ mPassthroughManager(passthroughManager) {
+
}
void Lshal::usage(const std::string &command) const {
NullableOStream<std::ostream> err) const {
using android::hidl::base::V1_0::IBase;
- hardware::Return<sp<IBase>> retBase =
- ::android::hardware::defaultServiceManager()->get(interfaceName, instanceName);
+ hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
if (!retBase.isOk()) {
std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": "
return USAGE;
}
+void signalHandler(int sig) {
+ if (sig == SIGINT) {
+ int retVal;
+ pthread_exit(&retVal);
+ }
+}
+
Status Lshal::main(const Arg &arg) {
+ // Allow SIGINT to terminate all threads.
+ signal(SIGINT, signalHandler);
+
Status status = parseArgs(arg);
if (status != OK) {
return status;
return mOut;
}
-void signalHandler(int sig) {
- if (sig == SIGINT) {
- int retVal;
- pthread_exit(&retVal);
- }
+const sp<IServiceManager> &Lshal::serviceManager() const {
+ return mServiceManager;
+}
+
+const sp<IServiceManager> &Lshal::passthroughManager() const {
+ return mPassthroughManager;
}
} // namespace lshal
} // namespace android
-
-int main(int argc, char **argv) {
- using namespace ::android::lshal;
- signal(SIGINT, signalHandler);
- return Lshal{}.main(Arg{argc, argv});
-}
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Lshal"
+#include <android-base/logging.h>
+
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <android/hardware/tests/baz/1.0/IQuux.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Lshal.h"
+
+#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
+
+using namespace testing;
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace baz {
+namespace V1_0 {
+namespace implementation {
+struct Quux : android::hardware::tests::baz::V1_0::IQuux {
+ ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
+ const native_handle_t *handle = hh.getNativeHandle();
+ if (handle->numFds < 1) {
+ return Void();
+ }
+ int fd = handle->data[0];
+ std::string content{descriptor};
+ for (const auto &option : options) {
+ content += "\n";
+ content += option.c_str();
+ }
+ ssize_t written = write(fd, content.c_str(), content.size());
+ if (written != (ssize_t)content.size()) {
+ LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
+ << content.size() << " bytes, errno = " << errno;
+ }
+ return Void();
+ }
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace baz
+} // namespace tests
+} // namespace hardware
+
+namespace lshal {
+
+
+class MockServiceManager : public IServiceManager {
+public:
+ template<typename T>
+ using R = ::android::hardware::Return<T>;
+ using String = const hidl_string&;
+ ~MockServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
+
+ MOCK_METHOD2(get, R<sp<IBase>>(String, String));
+ MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
+ MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
+ MOCK_METHOD_CB(list);
+ MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
+ MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
+ MOCK_METHOD_CB(debugDump);
+ MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
+ MOCK_METHOD_CB(interfaceChain);
+ MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
+ MOCK_METHOD_CB(interfaceDescriptor);
+ MOCK_METHOD_CB(getHashChain);
+ MOCK_METHOD0(setHalInstrumentation, R<void>());
+ MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
+ MOCK_METHOD0(ping, R<void>());
+ MOCK_METHOD_CB(getDebugInfo);
+ MOCK_METHOD0(notifySyspropsChanged, R<void>());
+ MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
+
+};
+
+class LshalTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ using ::android::hardware::tests::baz::V1_0::IQuux;
+ using ::android::hardware::tests::baz::V1_0::implementation::Quux;
+
+ err.str("");
+ out.str("");
+ serviceManager = new testing::NiceMock<MockServiceManager>();
+ ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+ [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
+ if (iface == IQuux::descriptor && inst == "default")
+ return new Quux();
+ return nullptr;
+ }));
+ }
+ void TearDown() override {}
+
+ std::stringstream err;
+ std::stringstream out;
+ sp<MockServiceManager> serviceManager;
+};
+
+TEST_F(LshalTest, Debug) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug2) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug3) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
+ };
+ EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(err.str(), HasSubstr("does not exist"));
+}
+
+} // namespace lshal
+} // namespace android
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}