Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / controller / java / AndroidDeviceControllerWrapper.cpp
1 /*
2  *   Copyright (c) 2020 Project CHIP Authors
3  *   All rights reserved.
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 #include "AndroidDeviceControllerWrapper.h"
19 #include "CHIPJNIError.h"
20
21 #include <memory>
22
23 using chip::PersistentStorageResultDelegate;
24 using chip::Controller::DeviceCommissioner;
25
26 namespace {
27
28 bool FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature, jmethodID * methodId)
29 {
30     if ((env == nullptr) || (object == nullptr))
31     {
32         ChipLogError(Controller, "Missing java object for %s", methodName);
33         return false;
34     }
35
36     jclass javaClass = env->GetObjectClass(object);
37     if (javaClass == NULL)
38     {
39         ChipLogError(Controller, "Failed to get class for %s", methodName);
40         return false;
41     }
42
43     *methodId = env->GetMethodID(javaClass, methodName, methodSignature);
44     if (*methodId == NULL)
45     {
46         ChipLogError(Controller, "Failed to find method %s", methodName);
47         return false;
48     }
49
50     return true;
51 }
52
53 void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument)
54 {
55     jmethodID method;
56
57     if (!FindMethod(env, object, methodName, "(I)V", &method))
58     {
59         return;
60     }
61
62     env->ExceptionClear();
63     env->CallVoidMethod(object, method, argument);
64 }
65
66 CHIP_ERROR N2J_ByteArray(JNIEnv * env, const uint8_t * inArray, uint32_t inArrayLen, jbyteArray & outArray)
67 {
68     CHIP_ERROR err = CHIP_NO_ERROR;
69
70     outArray = env->NewByteArray((int) inArrayLen);
71     VerifyOrExit(outArray != NULL, err = CHIP_ERROR_NO_MEMORY);
72
73     env->ExceptionClear();
74     env->SetByteArrayRegion(outArray, 0, inArrayLen, (jbyte *) inArray);
75     VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
76
77 exit:
78     return err;
79 }
80
81 CHIP_ERROR N2J_NewStringUTF(JNIEnv * env, const char * inStr, size_t inStrLen, jstring & outString)
82 {
83     CHIP_ERROR err          = CHIP_NO_ERROR;
84     jbyteArray charArray    = NULL;
85     jstring utf8Encoding    = NULL;
86     jclass java_lang_String = NULL;
87     jmethodID ctor          = NULL;
88
89     err = N2J_ByteArray(env, reinterpret_cast<const uint8_t *>(inStr), inStrLen, charArray);
90     SuccessOrExit(err);
91
92     utf8Encoding = env->NewStringUTF("UTF-8");
93     VerifyOrExit(utf8Encoding != NULL, err = CHIP_ERROR_NO_MEMORY);
94
95     java_lang_String = env->FindClass("java/lang/String");
96     VerifyOrExit(java_lang_String != NULL, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND);
97
98     ctor = env->GetMethodID(java_lang_String, "<init>", "([BLjava/lang/String;)V");
99     VerifyOrExit(ctor != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
100
101     outString = (jstring) env->NewObject(java_lang_String, ctor, charArray, utf8Encoding);
102     VerifyOrExit(outString != NULL, err = CHIP_ERROR_NO_MEMORY);
103
104 exit:
105     // error code propagated from here, so clear any possible
106     // exceptions that arose here
107     env->ExceptionClear();
108
109     if (utf8Encoding != NULL)
110         env->DeleteLocalRef(utf8Encoding);
111     if (charArray != NULL)
112         env->DeleteLocalRef(charArray);
113
114     return err;
115 }
116
117 CHIP_ERROR N2J_NewStringUTF(JNIEnv * env, const char * inStr, jstring & outString)
118 {
119     return N2J_NewStringUTF(env, inStr, strlen(inStr), outString);
120 }
121
122 } // namespace
123
124 AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper()
125 {
126     if ((mJavaVM != nullptr) && (mJavaObjectRef != nullptr))
127     {
128         GetJavaEnv()->DeleteGlobalRef(mJavaObjectRef);
129     }
130     mController->Shutdown();
131 }
132
133 void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj)
134 {
135     mJavaVM        = vm;
136     mJavaObjectRef = GetJavaEnv()->NewGlobalRef(obj);
137 }
138
139 JNIEnv * AndroidDeviceControllerWrapper::GetJavaEnv()
140 {
141     if (mJavaVM == nullptr)
142     {
143         return nullptr;
144     }
145
146     JNIEnv * env = nullptr;
147     mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
148
149     return env;
150 }
151
152 AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj,
153                                                                              chip::NodeId nodeId, chip::System::Layer * systemLayer,
154                                                                              chip::Inet::InetLayer * inetLayer,
155                                                                              CHIP_ERROR * errInfoOnFailure)
156 {
157     if (errInfoOnFailure == nullptr)
158     {
159         ChipLogError(Controller, "Missing error info");
160         return nullptr;
161     }
162     if (systemLayer == nullptr)
163     {
164         ChipLogError(Controller, "Missing system layer");
165         *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT;
166         return nullptr;
167     }
168     if (inetLayer == nullptr)
169     {
170         ChipLogError(Controller, "Missing inet layer");
171         *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT;
172         return nullptr;
173     }
174
175     *errInfoOnFailure = CHIP_NO_ERROR;
176
177     std::unique_ptr<DeviceCommissioner> controller(new DeviceCommissioner());
178
179     if (!controller)
180     {
181         *errInfoOnFailure = CHIP_ERROR_NO_MEMORY;
182         return nullptr;
183     }
184     std::unique_ptr<AndroidDeviceControllerWrapper> wrapper(new AndroidDeviceControllerWrapper(std::move(controller)));
185
186     wrapper->SetJavaObjectRef(vm, deviceControllerObj);
187     wrapper->Controller()->SetUdpListenPort(CHIP_PORT + 1);
188     *errInfoOnFailure = wrapper->Controller()->Init(nodeId, wrapper.get(), wrapper.get(), systemLayer, inetLayer);
189
190     if (*errInfoOnFailure != CHIP_NO_ERROR)
191     {
192         return nullptr;
193     }
194
195     *errInfoOnFailure = wrapper->Controller()->ServiceEvents();
196
197     if (*errInfoOnFailure != CHIP_NO_ERROR)
198     {
199         return nullptr;
200     }
201
202     return wrapper.release();
203 }
204
205 void AndroidDeviceControllerWrapper::SendNetworkCredentials(const char * ssid, const char * password)
206 {
207     if (mCredentialsDelegate == nullptr)
208     {
209         ChipLogError(Controller, "No credential callback available to send Wi-Fi credentials.");
210         return;
211     }
212
213     ChipLogProgress(Controller, "Sending network credentials for %s...", ssid);
214     mCredentialsDelegate->SendNetworkCredentials(ssid, password);
215 }
216
217 void AndroidDeviceControllerWrapper::SendThreadCredentials(const chip::DeviceLayer::Internal::DeviceNetworkInfo & threadData)
218 {
219     if (mCredentialsDelegate == nullptr)
220     {
221         ChipLogError(Controller, "No credential callback available to send Thread credentials.");
222         return;
223     }
224
225     ChipLogProgress(Controller, "Sending Thread credentials for channel %u, PAN ID %x...", threadData.ThreadChannel,
226                     threadData.ThreadPANId);
227     mCredentialsDelegate->SendThreadCredentials(threadData);
228 }
229
230 void AndroidDeviceControllerWrapper::OnNetworkCredentialsRequested(chip::RendezvousDeviceCredentialsDelegate * callback)
231 {
232     mCredentialsDelegate = callback;
233
234     JNIEnv * env = GetJavaEnv();
235
236     jmethodID method;
237     if (!FindMethod(env, mJavaObjectRef, "onNetworkCredentialsRequested", "()V", &method))
238     {
239         return;
240     }
241
242     env->ExceptionClear();
243     env->CallVoidMethod(mJavaObjectRef, method);
244 }
245
246 void AndroidDeviceControllerWrapper::OnOperationalCredentialsRequested(const char * csr, size_t csr_length,
247                                                                        chip::RendezvousDeviceCredentialsDelegate * callback)
248 {
249     mCredentialsDelegate = callback;
250
251     JNIEnv * env = GetJavaEnv();
252
253     jbyteArray jCsr;
254     if (!N2J_ByteArray(env, reinterpret_cast<const uint8_t *>(csr), csr_length, jCsr))
255     {
256         ChipLogError(Controller, "Failed to build byte array for operational credential request");
257         return;
258     }
259
260     jmethodID method;
261     if (!FindMethod(env, mJavaObjectRef, "onOperationalCredentialsRequested", "([B)V", &method))
262     {
263         return;
264     }
265
266     env->ExceptionClear();
267     env->CallVoidMethod(mJavaObjectRef, method, jCsr);
268 }
269
270 void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::RendezvousSessionDelegate::Status status)
271 {
272     CallVoidInt(GetJavaEnv(), mJavaObjectRef, "onStatusUpdate", static_cast<jint>(status));
273 }
274
275 void AndroidDeviceControllerWrapper::OnPairingComplete(CHIP_ERROR error)
276 {
277     CallVoidInt(GetJavaEnv(), mJavaObjectRef, "onPairingComplete", static_cast<jint>(error));
278 }
279
280 void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error)
281 {
282     CallVoidInt(GetJavaEnv(), mJavaObjectRef, "onPairingDeleted", static_cast<jint>(error));
283 }
284
285 void AndroidDeviceControllerWrapper::OnMessage(chip::System::PacketBufferHandle msg) {}
286
287 void AndroidDeviceControllerWrapper::OnStatusChange(void) {}
288
289 void AndroidDeviceControllerWrapper::SetStorageDelegate(PersistentStorageResultDelegate * delegate)
290 {
291     mStorageResultDelegate = delegate;
292 }
293
294 CHIP_ERROR AndroidDeviceControllerWrapper::SyncGetKeyValue(const char * key, char * value, uint16_t & size)
295 {
296     jstring keyString       = NULL;
297     jstring valueString     = NULL;
298     const char * valueChars = nullptr;
299     CHIP_ERROR err          = CHIP_NO_ERROR;
300     jclass storageCls       = GetPersistentStorageClass();
301     jmethodID method        = GetJavaEnv()->GetStaticMethodID(storageCls, "getKeyValue", "(Ljava/lang/String;)Ljava/lang/String;");
302
303     GetJavaEnv()->ExceptionClear();
304
305     err = N2J_NewStringUTF(GetJavaEnv(), key, keyString);
306     SuccessOrExit(err);
307
308     valueString = (jstring) GetJavaEnv()->CallStaticObjectMethod(storageCls, method, keyString);
309
310     if (valueString != NULL)
311     {
312         size_t stringLength = GetJavaEnv()->GetStringUTFLength(valueString);
313         if (stringLength > UINT16_MAX - 1)
314         {
315             err = CHIP_ERROR_BUFFER_TOO_SMALL;
316         }
317         else
318         {
319             if (value != nullptr)
320             {
321                 valueChars = GetJavaEnv()->GetStringUTFChars(valueString, 0);
322                 size       = strlcpy(value, valueChars, size);
323                 if (size < stringLength)
324                 {
325                     err = CHIP_ERROR_NO_MEMORY;
326                 }
327             }
328             else
329             {
330                 size = stringLength;
331                 err  = CHIP_ERROR_NO_MEMORY;
332             }
333             // Increment size to account for null termination
334             size += 1;
335         }
336     }
337     else
338     {
339         err = CHIP_ERROR_INVALID_ARGUMENT;
340     }
341
342 exit:
343     GetJavaEnv()->ExceptionClear();
344     if (valueChars != nullptr)
345     {
346         GetJavaEnv()->ReleaseStringUTFChars(valueString, valueChars);
347     }
348     GetJavaEnv()->DeleteLocalRef(keyString);
349     GetJavaEnv()->DeleteLocalRef(valueString);
350     return err;
351 }
352
353 void AndroidDeviceControllerWrapper::AsyncSetKeyValue(const char * key, const char * value)
354 {
355     jclass storageCls = GetPersistentStorageClass();
356     jmethodID method  = GetJavaEnv()->GetStaticMethodID(storageCls, "setKeyValue", "(Ljava/lang/String;Ljava/lang/String;)V");
357
358     GetJavaEnv()->ExceptionClear();
359
360     jstring keyString   = NULL;
361     jstring valueString = NULL;
362     CHIP_ERROR err      = CHIP_NO_ERROR;
363
364     err = N2J_NewStringUTF(GetJavaEnv(), key, keyString);
365     SuccessOrExit(err);
366     err = N2J_NewStringUTF(GetJavaEnv(), value, valueString);
367     SuccessOrExit(err);
368
369     GetJavaEnv()->CallStaticVoidMethod(storageCls, method, keyString, valueString);
370
371     if (mStorageResultDelegate)
372     {
373         mStorageResultDelegate->OnPersistentStorageStatus(key, PersistentStorageResultDelegate::Operation::kSET, CHIP_NO_ERROR);
374     }
375
376 exit:
377     GetJavaEnv()->ExceptionClear();
378     GetJavaEnv()->DeleteLocalRef(keyString);
379     GetJavaEnv()->DeleteLocalRef(valueString);
380 }
381
382 void AndroidDeviceControllerWrapper::AsyncDeleteKeyValue(const char * key)
383 {
384     jclass storageCls = GetPersistentStorageClass();
385     jmethodID method  = GetJavaEnv()->GetStaticMethodID(storageCls, "deleteKeyValue", "(Ljava/lang/String;)V");
386
387     GetJavaEnv()->ExceptionClear();
388
389     jstring keyString = NULL;
390     CHIP_ERROR err    = CHIP_NO_ERROR;
391
392     err = N2J_NewStringUTF(GetJavaEnv(), key, keyString);
393     SuccessOrExit(err);
394
395     GetJavaEnv()->CallStaticVoidMethod(storageCls, method, keyString);
396
397     if (mStorageResultDelegate)
398     {
399         mStorageResultDelegate->OnPersistentStorageStatus(key, PersistentStorageResultDelegate::Operation::kDELETE, CHIP_NO_ERROR);
400     }
401
402 exit:
403     GetJavaEnv()->ExceptionClear();
404     GetJavaEnv()->DeleteLocalRef(keyString);
405 }