/****************************************************************************** * * 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 #include #include #include #include #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> kAppletId; /* Interface instance of libese-transport library */ static std::unique_ptr pTransportFactory = nullptr; /** * \brief static inline function to get lib-ese-transport interface instance */ static inline std::unique_ptr & getTransportFactoryInstance() { if (pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr( 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> 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 data, std::vector &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 data, std::vector &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 data, std::vector &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; }