blob: a85a8bcad8928fdaf2ebda10516dc5fd29bef83e [file] [log] [blame]
/*
* Copyright (C) 2022 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 <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/secure_element/BnSecureElementCallback.h>
#include <aidl/android/hardware/secure_element/ISecureElement.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
using namespace std::chrono_literals;
using aidl::android::hardware::secure_element::BnSecureElementCallback;
using aidl::android::hardware::secure_element::ISecureElement;
using aidl::android::hardware::secure_element::LogicalChannelResponse;
using ndk::ScopedAStatus;
using ndk::SharedRefBase;
using ndk::SpAIBinder;
using testing::ElementsAre;
using testing::ElementsAreArray;
#define EXPECT_OK(status) \
do { \
auto status_impl = (status); \
EXPECT_TRUE(status_impl.isOk()) << status_impl.getDescription(); \
} while (false)
static const std::vector<uint8_t> kDataApdu = {0x00, 0x08, 0x00, 0x00, 0x00};
static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
0x43, 0x54, 0x53, 0x31};
class MySecureElementCallback : public BnSecureElementCallback {
public:
ScopedAStatus onStateChange(bool state, const std::string& debugReason) override {
{
std::unique_lock<std::mutex> l(m);
(void)debugReason;
history.push_back(state);
}
cv.notify_one();
return ScopedAStatus::ok();
};
void expectCallbackHistory(std::vector<bool>&& want) {
std::unique_lock<std::mutex> l(m);
cv.wait_for(l, 2s, [&]() { return history.size() >= want.size(); });
EXPECT_THAT(history, ElementsAreArray(want));
}
private:
std::mutex m; // guards history
std::condition_variable cv;
std::vector<bool> history;
};
class SecureElementAidl : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
SpAIBinder binder = SpAIBinder(AServiceManager_waitForService(GetParam().c_str()));
se = ISecureElement::fromBinder(binder);
ASSERT_NE(se, nullptr);
cb = SharedRefBase::make<MySecureElementCallback>();
EXPECT_OK(se->init(cb));
cb->expectCallbackHistory({true});
}
std::shared_ptr<ISecureElement> se;
std::shared_ptr<MySecureElementCallback> cb;
};
TEST_P(SecureElementAidl, isCardPresent) {
bool res = false;
EXPECT_OK(se->isCardPresent(&res));
EXPECT_TRUE(res);
}
TEST_P(SecureElementAidl, transmit) {
LogicalChannelResponse response;
EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
EXPECT_GE(response.selectResponse.size(), 2u);
EXPECT_GE(response.channelNumber, 1);
std::vector<uint8_t> command = kDataApdu;
command[0] |= response.channelNumber;
std::vector<uint8_t> transmitResponse;
EXPECT_OK(se->transmit(command, &transmitResponse));
EXPECT_LE(transmitResponse.size(), 3);
EXPECT_GE(transmitResponse.size(), 2);
EXPECT_EQ(transmitResponse[transmitResponse.size() - 1], 0x00);
EXPECT_EQ(transmitResponse[transmitResponse.size() - 2], 0x90);
EXPECT_OK(se->closeChannel(response.channelNumber));
}
TEST_P(SecureElementAidl, openBasicChannel) {
std::vector<uint8_t> response;
auto status = se->openBasicChannel(kAndroidTestAid, 0x00, &response);
if (!status.isOk()) {
EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::CHANNEL_NOT_AVAILABLE)
<< status.getDescription();
return;
}
EXPECT_GE(response.size(), 2u);
EXPECT_OK(se->closeChannel(0));
}
TEST_P(SecureElementAidl, getAtr) {
std::vector<uint8_t> atr;
EXPECT_OK(se->getAtr(&atr));
if (atr.size() == 0) {
return;
}
EXPECT_LE(atr.size(), 32u);
EXPECT_GE(atr.size(), 1u);
}
TEST_P(SecureElementAidl, openCloseLogicalChannel) {
LogicalChannelResponse response;
EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
EXPECT_GE(response.selectResponse.size(), 2u);
EXPECT_GE(response.channelNumber, 1);
EXPECT_OK(se->closeChannel(response.channelNumber));
}
TEST_P(SecureElementAidl, openInvalidAid) {
LogicalChannelResponse response;
auto status = se->openLogicalChannel({0x42}, 0x00, &response);
EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::NO_SUCH_ELEMENT_ERROR)
<< status.getDescription();
}
TEST_P(SecureElementAidl, Reset) {
cb->expectCallbackHistory({true});
EXPECT_OK(se->reset());
cb->expectCallbackHistory({true, false, true});
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SecureElementAidl);
INSTANTIATE_TEST_SUITE_P(
SecureElement, SecureElementAidl,
testing::ValuesIn(android::getAidlHalInstanceNames(ISecureElement::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}