1 /*
2 * Copyright (C) 2023 The Android Open Source Project.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "NativeWlcManager.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <cutils/properties.h>
22 #include <errno.h>
23 #include <nativehelper/JNIPlatformHelp.h>
24 #include <nativehelper/ScopedLocalRef.h>
25 #include <nativehelper/ScopedPrimitiveArray.h>
26 #include <nativehelper/ScopedUtfChars.h>
27 #include <semaphore.h>
28
29 #include "JavaClassConstants.h"
30 #include "NfcJniUtil.h"
31 #include "SyncEvent.h"
32 #include "nfa_api.h"
33
34 using android::base::StringPrintf;
35
36 /*****************************************************************************
37 **
38 ** private variables and functions
39 **
40 *****************************************************************************/
41
42 static void nfaWlcManagementCallback(tNFA_WLC_EVT wlcEvent,
43 tNFA_WLC_EVT_DATA* eventData);
44
45 static SyncEvent sNfaWlcEnableEvent; // event for NFA_WlcStart()
46 static SyncEvent sNfaWlcEvent; // event for NFA_Wlc...()
47
48 static bool sIsWlcpStarted = false;
49
50 Mutex gMutexWlc;
51
52 const JNINativeMethod NativeWlcManager::sMethods[] = {
53
54 {"startWlcPowerTransfer", "(II)Z",
55 (void*)NativeWlcManager::com_android_nfc_wlc_chargeWlcListener},
56 {"enableWlc", "(I)Z",
57 (void*)NativeWlcManager::com_android_nfc_wlc_startWlcP},
58
59 };
60
61 /*******************************************************************************
62 **
63 ** Function: NativeWlcManager
64 **
65 ** Description: Initialize member variables.
66 **
67 ** Returns: None
68 **
69 *******************************************************************************/
NativeWlcManager()70 NativeWlcManager::NativeWlcManager()
71 : mNativeData(NULL), mIsWlcEnabled(false) {}
72
73 /*******************************************************************************
74 **
75 ** Function: ~NativeWlcManager
76 **
77 ** Description: Release all resources.
78 **
79 ** Returns: None
80 **
81 *******************************************************************************/
~NativeWlcManager()82 NativeWlcManager::~NativeWlcManager() {}
83
84 /*******************************************************************************
85 **
86 ** Function: getInstance
87 **
88 ** Description: Get a reference to the singleton NativeWlcManager object.
89 **
90 ** Returns: Reference to NativeWlcManager object.
91 **
92 *******************************************************************************/
getInstance()93 NativeWlcManager& NativeWlcManager::getInstance() {
94 static NativeWlcManager manager;
95 return manager;
96 }
97
98 /*******************************************************************************
99 **
100 ** Function: initialize
101 **
102 ** Description: Reset member variables.
103 ** native: Native data.
104 **
105 ** Returns: None
106 **
107 *******************************************************************************/
initialize(nfc_jni_native_data * native)108 void NativeWlcManager::initialize(nfc_jni_native_data* native) {
109 tNFA_STATUS stat = NFA_STATUS_FAILED;
110
111 LOG(DEBUG) << StringPrintf("%s: enter", __func__);
112
113 mNativeData = native;
114 mIsWlcEnabled = false;
115
116 SyncEventGuard g(sNfaWlcEnableEvent);
117 // TODO: only do it once at NfcManager init if WLC allowed
118 stat = NFA_WlcEnable(nfaWlcManagementCallback);
119
120 if (stat == NFA_STATUS_OK) {
121 // TODO: get enable result to stop directly if failed
122 sNfaWlcEnableEvent.wait();
123 LOG(DEBUG) << StringPrintf("%s: enable Wlc module success", __func__);
124 } else {
125 LOG(ERROR) << StringPrintf("%s: fail enable Wlc module; error=0x%X",
126 __func__, stat);
127 }
128 }
129
130 /*******************************************************************************
131 **
132 ** Function: notifyWlcCompletion
133 **
134 ** Description: Notify end of WLC procedure.
135 ** wpt_end_condition: End condition from NFCC.
136 **
137 ** Returns: None
138 **
139 *******************************************************************************/
notifyWlcCompletion(uint8_t wpt_end_condition)140 void NativeWlcManager::notifyWlcCompletion(uint8_t wpt_end_condition) {
141 JNIEnv* e = NULL;
142 ScopedAttach attach(mNativeData->vm, &e);
143 if (e == NULL) {
144 LOG(ERROR) << "jni env is null";
145 return;
146 }
147
148 LOG(DEBUG) << StringPrintf("%s: ", __func__);
149
150 e->CallVoidMethod(mNativeData->manager,
151 android::gCachedNfcManagerNotifyWlcStopped,
152 (int)wpt_end_condition);
153 if (e->ExceptionCheck()) {
154 e->ExceptionClear();
155 LOG(ERROR) << StringPrintf("fail notify");
156 }
157 }
158
159 /*******************************************************************************
160 **
161 ** Function: nfaWlcManagementCallback
162 **
163 ** Description: Receive Wlc management events from stack.
164 ** wlcEvent: Wlc-management event ID.
165 ** eventData: Data associated with event ID.
166 **
167 ** Returns: None
168 **
169 *******************************************************************************/
nfaWlcManagementCallback(tNFA_WLC_EVT wlcEvent,tNFA_WLC_EVT_DATA * eventData)170 void nfaWlcManagementCallback(tNFA_WLC_EVT wlcEvent,
171 tNFA_WLC_EVT_DATA* eventData) {
172 LOG(DEBUG) << StringPrintf("%s: enter; event=0x%X", __func__, wlcEvent);
173
174 switch (wlcEvent) {
175 case NFA_WLC_ENABLE_RESULT_EVT: // whether WLC module enabled
176 {
177 LOG(DEBUG) << StringPrintf("%s: NFA_WLC_ENABLE_RESULT_EVT: status = %u",
178 __func__, eventData->status);
179
180 SyncEventGuard guard(sNfaWlcEnableEvent);
181 sNfaWlcEnableEvent.notifyOne();
182 } break;
183
184 case NFA_WLC_START_RESULT_EVT: // whether WLCP successfully started
185 {
186 LOG(DEBUG) << StringPrintf("%s: NFA_WLC_START_RESULT_EVT: status = %u",
187 __func__, eventData->status);
188
189 sIsWlcpStarted = eventData->status == NFA_STATUS_OK;
190 SyncEventGuard guard(sNfaWlcEvent);
191 sNfaWlcEvent.notifyOne();
192 } break;
193
194 case NFA_WLC_START_WPT_RESULT_EVT: // whether WLC Power Transfer
195 // successfully started
196 {
197 LOG(DEBUG) << StringPrintf(
198 "%s: NFA_WLC_START_WPT_RESULT_EVT: status = %u", __func__,
199 eventData->status);
200
201 SyncEventGuard guard(sNfaWlcEvent);
202 sNfaWlcEvent.notifyOne();
203 } break;
204
205 case NFA_WLC_CHARGING_RESULT_EVT: // notify completion of power transfer
206 // phase
207 {
208 LOG(DEBUG) << StringPrintf(
209 "%s: NFA_WLC_CHARGING_RESULT_EVT: End Condition = 0x%x", __func__,
210 eventData->wpt_end_cdt);
211
212 /* Return WPT end condition to service */
213 NativeWlcManager::getInstance().notifyWlcCompletion(
214 eventData->wpt_end_cdt);
215 } break;
216
217 default:
218 LOG(DEBUG) << StringPrintf("%s: unhandled event", __func__);
219 break;
220 }
221 }
222
223 /*******************************************************************************
224 **
225 ** Function: com_android_nfc_wlc_startWlcP
226 **
227 ** Description: Start WLC Poller
228 ** e: JVM environment.
229 ** mode: WLC mode
230 **
231 ** Returns: True if WLCP started done
232 **
233 *******************************************************************************/
com_android_nfc_wlc_startWlcP(JNIEnv * e,jobject,jint mode)234 jboolean NativeWlcManager::com_android_nfc_wlc_startWlcP(JNIEnv* e, jobject,
235 jint mode) {
236 tNFA_STATUS stat = NFA_STATUS_FAILED;
237
238 LOG(DEBUG) << StringPrintf("%s: enter", __func__);
239
240 gMutexWlc.lock();
241 SyncEventGuard g(sNfaWlcEvent);
242 stat = NFA_WlcStart(mode);
243
244 if (stat == NFA_STATUS_OK) {
245 LOG(DEBUG) << StringPrintf(
246 "%s: start Wlc Poller, wait for success confirmation", __func__);
247 sNfaWlcEvent.wait();
248 } else {
249 LOG(ERROR) << StringPrintf("%s: fail start WlcPoller; error=0x%X", __func__,
250 stat);
251 }
252 gMutexWlc.unlock();
253 return sIsWlcpStarted ? JNI_TRUE : JNI_FALSE;
254 }
255
256 /*******************************************************************************
257 **
258 ** Function: com_android_nfc_wlc_chargeWlcListener
259 **
260 ** Description: Start charging WLC Listener
261 ** e: JVM environment.
262 ** power_adj_req:
263 ** wpt_time_int:
264 **
265 ** Returns: True if WLCL charging started properly
266 **
267 *******************************************************************************/
com_android_nfc_wlc_chargeWlcListener(JNIEnv * e,jobject,jint power_adj_req,jint wpt_time_int)268 jboolean NativeWlcManager::com_android_nfc_wlc_chargeWlcListener(
269 JNIEnv* e, jobject, jint power_adj_req, jint wpt_time_int) {
270 tNFA_STATUS stat = NFA_STATUS_FAILED;
271
272 LOG(DEBUG) << StringPrintf("%s: wpt_time_int = %d", __func__, wpt_time_int);
273
274 gMutexWlc.lock();
275 SyncEventGuard g(sNfaWlcEvent);
276 // TODO: condition call to sIsWlcpStarted
277 // TODO: limit the min of wpt_time_int
278 stat = NFA_WlcStartWPT((uint16_t)(power_adj_req & 0xFFFF), wpt_time_int);
279 if (stat == NFA_STATUS_OK) {
280 LOG(DEBUG) << StringPrintf(
281 "%s: charge Wlc Listener, wait for success confirmation", __func__);
282 sNfaWlcEvent.wait();
283 } else {
284 LOG(ERROR) << StringPrintf("%s: fail charge Wlc Listener; error=0x%X",
285 __func__, stat);
286 gMutexWlc.unlock();
287 return false;
288 }
289 gMutexWlc.unlock();
290 return true;
291 }
292
293 /*******************************************************************************
294 **
295 ** Function: registerJniFunctions
296 **
297 ** Description: Register WLC feature JNI functions
298 ** e: JVM environment.
299 **
300 ** Returns: -1 if JNI register error
301 **
302 *******************************************************************************/
registerJniFunctions(JNIEnv * e)303 int NativeWlcManager::registerJniFunctions(JNIEnv* e) {
304 static const char fn[] = "NativeWlcManager::registerJniFunctions";
305 LOG(DEBUG) << StringPrintf("%s", fn);
306 return jniRegisterNativeMethods(e, "com/android/nfc/wlc/NfcCharging",
307 sMethods, NELEM(sMethods));
308 }
309