blob: 08f4fd0e3ea1d4109adf25830106f6a253b2f0d4 [file]
/******************************************************************************
*
* Copyright 2020-2023 NXP
*
* 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 "weaver-transport-impl"
#include <TransportFactory.h>
#include <cutils/properties.h>
#include <vector>
#include <weaver_transport-impl.h>
#include <weaver_utils.h>
#define MAX_RETRY_COUNT 12
#define RETRY_DELAY_INTERVAL_SEC 1
#define PROP_SYSBOOT_COMPLETED "sys.boot_completed"
#define SYSBOOT_COMPLETED_VALUE 1
#define IS_APPLET_SELECTION_FAILED(resp) \
(!resp.empty() && resp[0] == APP_NOT_FOUND_SW1 && \
resp[1] == APP_NOT_FOUND_SW2)
WeaverTransportImpl *WeaverTransportImpl::s_instance = NULL;
std::once_flag WeaverTransportImpl::s_instanceFlag;
/* Applet ID to be use for communication */
std::vector<std::vector<uint8_t>> kAppletId;
/* Interface instance of libese-transport library */
static std::unique_ptr<se_transport::TransportFactory> pTransportFactory =
nullptr;
/**
* \brief static inline function to get lib-ese-transport interface instance
*/
static inline std::unique_ptr<se_transport::TransportFactory> &
getTransportFactoryInstance() {
if (pTransportFactory == nullptr) {
pTransportFactory = std::unique_ptr<se_transport::TransportFactory>(
new se_transport::TransportFactory(false, kAppletId[0]));
pTransportFactory->openConnection();
}
return pTransportFactory;
}
/**
* \brief static function to get the singleton instance of WeaverTransportImpl
* class
*
* \retval instance of WeaverTransportImpl.
*/
WeaverTransportImpl *WeaverTransportImpl::getInstance() {
/* call_once c++11 api which executes the passed function ptr exactly once,
* even if called concurrently, from several threads
*/
std::call_once(s_instanceFlag, &WeaverTransportImpl::createInstance);
return s_instance;
}
/* Private function to create the instance of self class
* Same will be used for std::call_once
*/
void WeaverTransportImpl::createInstance() {
LOG_D(TAG, "Entry");
s_instance = new WeaverTransportImpl;
LOG_D(TAG, "Exit");
}
/**
* \brief Function to initialize Weaver Transport Interface
*
* \param[in] aid - applet id to be set to transport interface
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::Init(std::vector<std::vector<uint8_t>> aid) {
LOG_D(TAG, "Entry");
kAppletId = std::move(aid);
LOG_D(TAG, "Exit");
return true;
}
/**
* \brief Function to open applet connection
*
* \param[in] data - command for open applet
* \param[out] resp - response from applet
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::OpenApplet(std::vector<uint8_t> data,
std::vector<uint8_t> &resp) {
LOG_D(TAG, "Entry");
bool status = true;
UNUSED(data);
UNUSED(resp);
// Since libese_transport opens channel as part of send only so open applet is
// not required
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to close applet connection
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::CloseApplet() {
LOG_D(TAG, "Entry");
// Close the Applet Channel if opened
bool status = getTransportFactoryInstance()->closeConnection();
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Private wrapper function to send apdu.
* It will try with alternate aids if sending is failed.
*
* \param[in] data - command to be send to applet
* \param[out] resp - response from applet
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::sendInternal(std::vector<uint8_t> data,
std::vector<uint8_t> &resp) {
bool status = false;
status =
getTransportFactoryInstance()->sendData(data.data(), data.size(), resp);
if (!status && IS_APPLET_SELECTION_FAILED(resp)) {
LOG_E(TAG, ": send Failed, trying with alternateAids");
// If Applet selection failed, try with alternate Aids
for (int i = 1; i < kAppletId.size(); i++) {
getTransportFactoryInstance()->setAppletAid(kAppletId[i]);
status = getTransportFactoryInstance()->sendData(data.data(), data.size(),
resp);
if (status) {
return status;
}
}
if (!status) {
// None of alternate Aids success, Revert back to primary AID
getTransportFactoryInstance()->setAppletAid(kAppletId[0]);
}
}
return status;
}
/**
* \brief Function to send commands to applet
*
* \param[in] data - command to be send to applet
* \param[out] resp - response from applet
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::Send(std::vector<uint8_t> data,
std::vector<uint8_t> &resp) {
LOG_D(TAG, "Entry");
int retry = 1;
bool status = false;
// Opens the channel with aid and transmit the data
do {
status = sendInternal(data, resp);
if (!status) {
if (!isDeviceBootCompleted()) {
LOG_D(TAG, ": Device boot not completed, no retry required");
break;
}
if (retry > MAX_RETRY_COUNT) {
LOG_E(TAG, ": completed max retries exit failure");
} else {
sleep(RETRY_DELAY_INTERVAL_SEC);
LOG_E(TAG, ": retry %d/%d", retry, MAX_RETRY_COUNT);
}
}
} while ((!status) && (retry++ <= MAX_RETRY_COUNT));
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to de-initialize Weaver Transport Interface
*
* \retval This function return true in case of success
* In case of failure returns false.
*/
bool WeaverTransportImpl::DeInit() {
LOG_D(TAG, "Entry");
bool status = CloseApplet();
LOG_D(TAG, "Exit");
return status;
}
/**
* \brief Function to determine if phone boot completed
*
* \retval This function return true in case of phone boot
* completed and false in case not completed.
*/
bool WeaverTransportImpl::isDeviceBootCompleted() {
if (property_get_int64(PROP_SYSBOOT_COMPLETED, 0) ==
SYSBOOT_COMPLETED_VALUE) {
return true;
}
return false;
}