1 /******************************************************************************
2 *
3 * Copyright 2020-2023 NXP
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "weaver-transport-impl"
20 #include <TransportFactory.h>
21 #include <cutils/properties.h>
22 #include <vector>
23 #include <weaver_transport-impl.h>
24 #include <weaver_utils.h>
25
26 #define MAX_RETRY_COUNT 12
27 #define RETRY_DELAY_INTERVAL_SEC 1
28 #define PROP_SYSBOOT_COMPLETED "sys.boot_completed"
29 #define SYSBOOT_COMPLETED_VALUE 1
30 #define IS_APPLET_SELECTION_FAILED(resp) \
31 (!resp.empty() && resp[0] == APP_NOT_FOUND_SW1 && \
32 resp[1] == APP_NOT_FOUND_SW2)
33
34 WeaverTransportImpl *WeaverTransportImpl::s_instance = NULL;
35 std::once_flag WeaverTransportImpl::s_instanceFlag;
36
37 /* Applet ID to be use for communication */
38 std::vector<std::vector<uint8_t>> kAppletId;
39
40 /* Interface instance of libese-transport library */
41 static std::unique_ptr<se_transport::TransportFactory> pTransportFactory =
42 nullptr;
43
44 /**
45 * \brief static inline function to get lib-ese-transport interface instance
46 */
47 static inline std::unique_ptr<se_transport::TransportFactory> &
getTransportFactoryInstance()48 getTransportFactoryInstance() {
49 if (pTransportFactory == nullptr) {
50 pTransportFactory = std::unique_ptr<se_transport::TransportFactory>(
51 new se_transport::TransportFactory(false, kAppletId[0]));
52 pTransportFactory->openConnection();
53 }
54 return pTransportFactory;
55 }
56
57 /**
58 * \brief static function to get the singleton instance of WeaverTransportImpl
59 * class
60 *
61 * \retval instance of WeaverTransportImpl.
62 */
getInstance()63 WeaverTransportImpl *WeaverTransportImpl::getInstance() {
64 /* call_once c++11 api which executes the passed function ptr exactly once,
65 * even if called concurrently, from several threads
66 */
67 std::call_once(s_instanceFlag, &WeaverTransportImpl::createInstance);
68 return s_instance;
69 }
70
71 /* Private function to create the instance of self class
72 * Same will be used for std::call_once
73 */
createInstance()74 void WeaverTransportImpl::createInstance() {
75 LOG_D(TAG, "Entry");
76 s_instance = new WeaverTransportImpl;
77 LOG_D(TAG, "Exit");
78 }
79
80 /**
81 * \brief Function to initialize Weaver Transport Interface
82 *
83 * \param[in] aid - applet id to be set to transport interface
84 *
85 * \retval This function return true in case of success
86 * In case of failure returns false.
87 */
Init(std::vector<std::vector<uint8_t>> aid)88 bool WeaverTransportImpl::Init(std::vector<std::vector<uint8_t>> aid) {
89 LOG_D(TAG, "Entry");
90 kAppletId = std::move(aid);
91 LOG_D(TAG, "Exit");
92 return true;
93 }
94
95 /**
96 * \brief Function to open applet connection
97 *
98 * \param[in] data - command for open applet
99 * \param[out] resp - response from applet
100 *
101 * \retval This function return true in case of success
102 * In case of failure returns false.
103 */
OpenApplet(std::vector<uint8_t> data,std::vector<uint8_t> & resp)104 bool WeaverTransportImpl::OpenApplet(std::vector<uint8_t> data,
105 std::vector<uint8_t> &resp) {
106 LOG_D(TAG, "Entry");
107 bool status = true;
108 UNUSED(data);
109 UNUSED(resp);
110 // Since libese_transport opens channel as part of send only so open applet is
111 // not required
112 LOG_D(TAG, "Exit");
113 return status;
114 }
115
116 /**
117 * \brief Function to close applet connection
118 *
119 * \retval This function return true in case of success
120 * In case of failure returns false.
121 */
CloseApplet()122 bool WeaverTransportImpl::CloseApplet() {
123 LOG_D(TAG, "Entry");
124 // Close the Applet Channel if opened
125 bool status = getTransportFactoryInstance()->closeConnection();
126 LOG_D(TAG, "Exit");
127 return status;
128 }
129
130 /**
131 * \brief Private wrapper function to send apdu.
132 * It will try with alternate aids if sending is failed.
133 *
134 * \param[in] data - command to be send to applet
135 * \param[out] resp - response from applet
136 *
137 * \retval This function return true in case of success
138 * In case of failure returns false.
139 */
sendInternal(std::vector<uint8_t> data,std::vector<uint8_t> & resp)140 bool WeaverTransportImpl::sendInternal(std::vector<uint8_t> data,
141 std::vector<uint8_t> &resp) {
142 bool status = false;
143 status =
144 getTransportFactoryInstance()->sendData(data.data(), data.size(), resp);
145 if (!status && IS_APPLET_SELECTION_FAILED(resp)) {
146 LOG_E(TAG, ": send Failed, trying with alternateAids");
147 // If Applet selection failed, try with alternate Aids
148 for (int i = 1; i < kAppletId.size(); i++) {
149 getTransportFactoryInstance()->setAppletAid(kAppletId[i]);
150 status = getTransportFactoryInstance()->sendData(data.data(), data.size(),
151 resp);
152 if (status) {
153 return status;
154 }
155 }
156 if (!status) {
157 // None of alternate Aids success, Revert back to primary AID
158 getTransportFactoryInstance()->setAppletAid(kAppletId[0]);
159 }
160 }
161 return status;
162 }
163
164 /**
165 * \brief Function to send commands to applet
166 *
167 * \param[in] data - command to be send to applet
168 * \param[out] resp - response from applet
169 *
170 * \retval This function return true in case of success
171 * In case of failure returns false.
172 */
Send(std::vector<uint8_t> data,std::vector<uint8_t> & resp)173 bool WeaverTransportImpl::Send(std::vector<uint8_t> data,
174 std::vector<uint8_t> &resp) {
175 LOG_D(TAG, "Entry");
176 int retry = 1;
177 bool status = false;
178 // Opens the channel with aid and transmit the data
179 do {
180 status = sendInternal(data, resp);
181 if (!status) {
182 if (!isDeviceBootCompleted()) {
183 LOG_D(TAG, ": Device boot not completed, no retry required");
184 break;
185 }
186 if (retry > MAX_RETRY_COUNT) {
187 LOG_E(TAG, ": completed max retries exit failure");
188 } else {
189 sleep(RETRY_DELAY_INTERVAL_SEC);
190 LOG_E(TAG, ": retry %d/%d", retry, MAX_RETRY_COUNT);
191 }
192 }
193 } while ((!status) && (retry++ <= MAX_RETRY_COUNT));
194 LOG_D(TAG, "Exit");
195 return status;
196 }
197
198 /**
199 * \brief Function to de-initialize Weaver Transport Interface
200 *
201 * \retval This function return true in case of success
202 * In case of failure returns false.
203 */
DeInit()204 bool WeaverTransportImpl::DeInit() {
205 LOG_D(TAG, "Entry");
206 bool status = CloseApplet();
207 LOG_D(TAG, "Exit");
208 return status;
209 }
210
211 /**
212 * \brief Function to determine if phone boot completed
213 *
214 * \retval This function return true in case of phone boot
215 * completed and false in case not completed.
216 */
isDeviceBootCompleted()217 bool WeaverTransportImpl::isDeviceBootCompleted() {
218 if (property_get_int64(PROP_SYSBOOT_COMPLETED, 0) ==
219 SYSBOOT_COMPLETED_VALUE) {
220 return true;
221 }
222 return false;
223 }
224