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