android13/frameworks/native/services/inputflinger/tests/InputFlingerService_test.cpp

244 lines
7.4 KiB
C++

/*
* 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 <BnInputFlingerQuery.h>
#include <IInputFlingerQuery.h>
#include <android/os/BnInputFlinger.h>
#include <android/os/IInputFlinger.h>
#include <binder/Binder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <gtest/gtest.h>
#include <inttypes.h>
#include <linux/uinput.h>
#include <log/log.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <chrono>
#include <thread>
#include <unordered_map>
#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<IInputFlinger> mService;
sp<IInputFlingerQuery> mQuery;
private:
std::unique_ptr<InputChannel> 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<String16>& args) override;
binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
void reset();
private:
mutable Mutex mLock;
std::vector<std::shared_ptr<InputChannel>> mInputChannels;
};
class TestInputQuery : public BnInputFlingerQuery {
public:
TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
binder::Status resetInputManager() override;
private:
sp<android::TestInputManager> 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<InputChannel> serverChannel;
std::unique_ptr<InputChannel> 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<IBinder>& connectionToken) {
AutoMutex _l(mLock);
auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
[&](std::shared_ptr<InputChannel>& c) {
return c->getConnectionToken() == connectionToken;
});
if (it != mInputChannels.end()) {
mInputChannels.erase(it);
}
return binder::Status::ok();
}
status_t TestInputManager::dump(int fd, const Vector<String16>& 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<InputChannel>& 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<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName));
ASSERT_TRUE(input != nullptr);
mService = interface_cast<IInputFlinger>(input);
input = defaultServiceManager()->waitForService(kQueryServiceName);
ASSERT_TRUE(input != nullptr);
mQuery = interface_cast<IInputFlingerQuery>(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<android::TestInputManager> manager = new android::TestInputManager();
android::sp<android::TestInputQuery> 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;
}