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) << __func__ << ": 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("%s: fail notify", __func__);
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 switch (wlcEvent) {
173 case NFA_WLC_ENABLE_RESULT_EVT: // whether WLC module enabled
174 {
175 LOG(DEBUG) << StringPrintf("%s: NFA_WLC_ENABLE_RESULT_EVT: status = %u",
176 __func__, eventData->status);
177
178 SyncEventGuard guard(sNfaWlcEnableEvent);
179 sNfaWlcEnableEvent.notifyOne();
180 } break;
181
182 case NFA_WLC_START_RESULT_EVT: // whether WLCP successfully started
183 {
184 LOG(DEBUG) << StringPrintf("%s: NFA_WLC_START_RESULT_EVT: status = %u",
185 __func__, eventData->status);
186
187 sIsWlcpStarted = eventData->status == NFA_STATUS_OK;
188 SyncEventGuard guard(sNfaWlcEvent);
189 sNfaWlcEvent.notifyOne();
190 } break;
191
192 case NFA_WLC_START_WPT_RESULT_EVT: // whether WLC Power Transfer
193 // successfully started
194 {
195 LOG(DEBUG) << StringPrintf(
196 "%s: NFA_WLC_START_WPT_RESULT_EVT: status = %u", __func__,
197 eventData->status);
198
199 SyncEventGuard guard(sNfaWlcEvent);
200 sNfaWlcEvent.notifyOne();
201 } break;
202
203 case NFA_WLC_CHARGING_RESULT_EVT: // notify completion of power transfer
204 // phase
205 {
206 LOG(DEBUG) << StringPrintf(
207 "%s: NFA_WLC_CHARGING_RESULT_EVT: End Condition = 0x%x", __func__,
208 eventData->wpt_end_cdt);
209
210 /* Return WPT end condition to service */
211 NativeWlcManager::getInstance().notifyWlcCompletion(
212 eventData->wpt_end_cdt);
213 } break;
214
215 default:
216 LOG(DEBUG) << StringPrintf("%s: unhandled event", __func__);
217 break;
218 }
219 }
220
221 /*******************************************************************************
222 **
223 ** Function: com_android_nfc_wlc_startWlcP
224 **
225 ** Description: Start WLC Poller
226 ** e: JVM environment.
227 ** mode: WLC mode
228 **
229 ** Returns: True if WLCP started done
230 **
231 *******************************************************************************/
com_android_nfc_wlc_startWlcP(JNIEnv * e,jobject,jint mode)232 jboolean NativeWlcManager::com_android_nfc_wlc_startWlcP(JNIEnv* e, jobject,
233 jint mode) {
234 tNFA_STATUS stat = NFA_STATUS_FAILED;
235
236 LOG(DEBUG) << StringPrintf("%s: enter", __func__);
237
238 gMutexWlc.lock();
239 SyncEventGuard g(sNfaWlcEvent);
240 stat = NFA_WlcStart(mode);
241
242 if (stat == NFA_STATUS_OK) {
243 LOG(DEBUG) << StringPrintf(
244 "%s: start Wlc Poller, wait for success confirmation", __func__);
245 sNfaWlcEvent.wait();
246 } else {
247 LOG(ERROR) << StringPrintf("%s: fail start WlcPoller; error=0x%X", __func__,
248 stat);
249 }
250 gMutexWlc.unlock();
251 return sIsWlcpStarted ? JNI_TRUE : JNI_FALSE;
252 }
253
254 /*******************************************************************************
255 **
256 ** Function: com_android_nfc_wlc_chargeWlcListener
257 **
258 ** Description: Start charging WLC Listener
259 ** e: JVM environment.
260 ** power_adj_req:
261 ** wpt_time_int:
262 **
263 ** Returns: True if WLCL charging started properly
264 **
265 *******************************************************************************/
com_android_nfc_wlc_chargeWlcListener(JNIEnv * e,jobject,jint power_adj_req,jint wpt_time_int)266 jboolean NativeWlcManager::com_android_nfc_wlc_chargeWlcListener(
267 JNIEnv* e, jobject, jint power_adj_req, jint wpt_time_int) {
268 tNFA_STATUS stat = NFA_STATUS_FAILED;
269
270 LOG(DEBUG) << StringPrintf("%s: wpt_time_int = %d", __func__, wpt_time_int);
271
272 gMutexWlc.lock();
273 SyncEventGuard g(sNfaWlcEvent);
274 // TODO: condition call to sIsWlcpStarted
275 // TODO: limit the min of wpt_time_int
276 stat = NFA_WlcStartWPT((uint16_t)(power_adj_req & 0xFFFF), wpt_time_int);
277 if (stat == NFA_STATUS_OK) {
278 LOG(DEBUG) << StringPrintf(
279 "%s: charge Wlc Listener, wait for success confirmation", __func__);
280 sNfaWlcEvent.wait();
281 } else {
282 LOG(ERROR) << StringPrintf("%s: fail charge Wlc Listener; error=0x%X",
283 __func__, stat);
284 gMutexWlc.unlock();
285 return false;
286 }
287 gMutexWlc.unlock();
288 return true;
289 }
290
291 /*******************************************************************************
292 **
293 ** Function: registerJniFunctions
294 **
295 ** Description: Register WLC feature JNI functions
296 ** e: JVM environment.
297 **
298 ** Returns: -1 if JNI register error
299 **
300 *******************************************************************************/
registerJniFunctions(JNIEnv * e)301 int NativeWlcManager::registerJniFunctions(JNIEnv* e) {
302 static const char fn[] = "NativeWlcManager::registerJniFunctions";
303 LOG(DEBUG) << StringPrintf("%s", fn);
304 return jniRegisterNativeMethods(e, "com/android/nfc/wlc/NfcCharging",
305 sMethods, NELEM(sMethods));
306 }
307