/* * Copyright (C) 2020 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TAG "InputFlingerServiceTest" using android::gui::FocusRequest; using android::os::BnInputFlinger; using android::os::IInputFlinger; using std::chrono_literals::operator""ms; using std::chrono_literals::operator""s; namespace android { static const String16 kTestServiceName = String16("InputFlingerService"); static const String16 kQueryServiceName = String16("InputFlingerQueryService"); // --- InputFlingerServiceTest --- class InputFlingerServiceTest : public testing::Test { public: void SetUp() override; void TearDown() override; protected: void InitializeInputFlinger(); sp mService; sp mQuery; private: std::unique_ptr mServerChannel, mClientChannel; std::mutex mLock; }; class TestInputManager : public BnInputFlinger { protected: virtual ~TestInputManager(){}; public: TestInputManager(){}; binder::Status getInputChannels(std::vector<::android::InputChannel>* channels); status_t dump(int fd, const Vector& args) override; binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override; binder::Status removeInputChannel(const sp& connectionToken) override; binder::Status setFocusedWindow(const FocusRequest&) override; void reset(); private: mutable Mutex mLock; std::vector> mInputChannels; }; class TestInputQuery : public BnInputFlingerQuery { public: TestInputQuery(sp manager) : mManager(manager){}; binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override; binder::Status resetInputManager() override; private: sp mManager; }; binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannel>* channels) { return mManager->getInputChannels(channels); } binder::Status TestInputQuery::resetInputManager() { mManager->reset(); return binder::Status::ok(); } binder::Status TestInputManager::createInputChannel(const std::string& name, InputChannel* outChannel) { AutoMutex _l(mLock); std::unique_ptr serverChannel; std::unique_ptr clientChannel; InputChannel::openInputChannelPair(name, serverChannel, clientChannel); clientChannel->copyTo(*outChannel); mInputChannels.emplace_back(std::move(serverChannel)); return binder::Status::ok(); } binder::Status TestInputManager::removeInputChannel(const sp& connectionToken) { AutoMutex _l(mLock); auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(), [&](std::shared_ptr& c) { return c->getConnectionToken() == connectionToken; }); if (it != mInputChannels.end()) { mInputChannels.erase(it); } return binder::Status::ok(); } status_t TestInputManager::dump(int fd, const Vector& args) { std::string dump; dump += " InputFlinger dump\n"; ::write(fd, dump.c_str(), dump.size()); return NO_ERROR; } binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannel>* channels) { channels->clear(); for (std::shared_ptr& channel : mInputChannels) { channels->push_back(*channel); } return binder::Status::ok(); } binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) { return binder::Status::ok(); } void TestInputManager::reset() { mInputChannels.clear(); } void InputFlingerServiceTest::SetUp() { InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel); InitializeInputFlinger(); } void InputFlingerServiceTest::TearDown() { mQuery->resetInputManager(); } void InputFlingerServiceTest::InitializeInputFlinger() { sp input(defaultServiceManager()->waitForService(kTestServiceName)); ASSERT_TRUE(input != nullptr); mService = interface_cast(input); input = defaultServiceManager()->waitForService(kQueryServiceName); ASSERT_TRUE(input != nullptr); mQuery = interface_cast(input); } /** * Test InputFlinger service interface createInputChannel */ TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) { // Test that the unblocked file descriptor flag is kept across processes over binder // transactions. InputChannel channel; ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk()); const base::unique_fd& fd = channel.getFd(); ASSERT_TRUE(fd.ok()); const int result = fcntl(fd, F_GETFL); EXPECT_NE(result, -1); EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK); } TEST_F(InputFlingerServiceTest, CreateInputChannel) { InputChannel channel; ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk()); std::vector<::android::InputChannel> channels; mQuery->getInputChannels(&channels); ASSERT_EQ(channels.size(), 1UL); EXPECT_EQ(channels[0].getConnectionToken(), channel.getConnectionToken()); mService->removeInputChannel(channel.getConnectionToken()); mQuery->getInputChannels(&channels); EXPECT_EQ(channels.size(), 0UL); } } // namespace android int main(int argc, char** argv) { pid_t forkPid = fork(); if (forkPid == 0) { // Server process android::sp manager = new android::TestInputManager(); android::sp query = new android::TestInputQuery(manager); android::defaultServiceManager()->addService(android::kTestServiceName, manager, false /*allowIsolated*/); android::defaultServiceManager()->addService(android::kQueryServiceName, query, false /*allowIsolated*/); android::ProcessState::self()->startThreadPool(); android::IPCThreadState::self()->joinThreadPool(); } else { android::ProcessState::self()->startThreadPool(); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); kill(forkPid, SIGKILL); return result; } return 0; }