Skip to content

Commit

Permalink
Centralize JNI util functions into JniReferences and use GetEnvForCur…
Browse files Browse the repository at this point in the history
…rentThread everywhere. (#7345)
  • Loading branch information
austinh0 authored Jun 4, 2021
1 parent 8402293 commit aa96ea0
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 107 deletions.
61 changes: 3 additions & 58 deletions src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,79 +28,24 @@ using chip::Controller::DeviceCommissioner;

extern chip::Ble::BleLayer * GetJNIBleLayer();

namespace {

bool FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature, jmethodID * methodId)
{
if ((env == nullptr) || (object == nullptr))
{
ChipLogError(Controller, "Missing java object for %s", methodName);
return false;
}

jclass javaClass = env->GetObjectClass(object);
if (javaClass == NULL)
{
ChipLogError(Controller, "Failed to get class for %s", methodName);
return false;
}

*methodId = env->GetMethodID(javaClass, methodName, methodSignature);
if (*methodId == NULL)
{
ChipLogError(Controller, "Failed to find method %s", methodName);
return false;
}

return true;
}

void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument)
{
jmethodID method;

if (!FindMethod(env, object, methodName, "(I)V", &method))
{
return;
}

env->ExceptionClear();
env->CallVoidMethod(object, method, argument);
}

} // namespace

AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper()
{
if ((mJavaVM != nullptr) && (mJavaObjectRef != nullptr))
{
GetJavaEnv()->DeleteGlobalRef(mJavaObjectRef);
GetEnvForCurrentThread()->DeleteGlobalRef(mJavaObjectRef);
}
mController->Shutdown();
}

void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj)
{
mJavaVM = vm;
mJavaObjectRef = GetJavaEnv()->NewGlobalRef(obj);
mJavaObjectRef = GetEnvForCurrentThread()->NewGlobalRef(obj);
}

void AndroidDeviceControllerWrapper::CallJavaMethod(const char * methodName, jint argument)
{
CallVoidInt(GetJavaEnv(), mJavaObjectRef, methodName, argument);
}

JNIEnv * AndroidDeviceControllerWrapper::GetJavaEnv()
{
if (mJavaVM == nullptr)
{
return nullptr;
}

JNIEnv * env = nullptr;
mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_6);

return env;
CallVoidInt(GetEnvForCurrentThread(), mJavaObjectRef, methodName, argument);
}

AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(JavaVM * vm, jobject deviceControllerObj,
Expand Down
6 changes: 2 additions & 4 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
#pragma once

#include "JniReferences.h"

#include <memory>

#include <jni.h>
Expand Down Expand Up @@ -92,10 +94,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
JavaVM * mJavaVM = nullptr;
jobject mJavaObjectRef = nullptr;

JNIEnv * GetJavaEnv();

jclass GetPersistentStorageClass() { return GetJavaEnv()->FindClass("chip/devicecontroller/PersistentStorage"); }

AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, pthread_mutex_t * stackLock) :
mController(std::move(controller)), mStackLock(stackLock)
{}
Expand Down
20 changes: 0 additions & 20 deletions src/controller/java/AndroidKeyValueStoreManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,26 +148,6 @@ CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value,
return CHIP_NO_ERROR;
}

JNIEnv * KeyValueStoreManagerImpl::GetEnvForCurrentThread()
{
if (mJvm == nullptr)
{
ChipLogError(DeviceLayer, "Missing Java VM in persistent storage");
return nullptr;
}

JNIEnv * env = nullptr;

jint err = mJvm->AttachCurrentThread(&env, nullptr);
if (err != JNI_OK)
{
ChipLogError(DeviceLayer, "Failed to get JNIEnv for the current thread");
return nullptr;
}

return env;
}

void KeyValueStoreManagerImpl::InitializeMethodForward(JavaVM * vm, JNIEnv * env)
{
mJvm = vm;
Expand Down
2 changes: 0 additions & 2 deletions src/controller/java/AndroidKeyValueStoreManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ class KeyValueStoreManagerImpl : public KeyValueStoreManager
jmethodID mGetMethod = nullptr;
jmethodID mDeleteMethod = nullptr;

JNIEnv * GetEnvForCurrentThread();

// ===== Members for internal use by the following friends.
friend KeyValueStoreManager & KeyValueStoreMgr();
friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl();
Expand Down
41 changes: 18 additions & 23 deletions src/controller/java/CHIPDeviceController-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,12 @@ jint JNI_OnLoad(JavaVM * jvm, void * reserved)
chip::Platform::MemoryInit();

// Save a reference to the JVM. Will need this to call back into Java.
SetJavaVm(jvm);
sJVM = jvm;

// Get a JNI environment object.
sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
env = GetEnvForCurrentThread();
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().InitializeMethodForward(sJVM, env);

Expand Down Expand Up @@ -740,16 +742,15 @@ JNI_METHOD(void, deleteDeviceController)(JNIEnv * env, jobject self, jlong handl
void HandleNotifyChipConnectionClosed(BLE_CONNECTION_OBJECT connObj)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jmethodID method;
intptr_t tmpConnObj;

ChipLogProgress(Controller, "Received NotifyChipConnectionClosed");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

method = env->GetStaticMethodID(sAndroidChipStackCls, "onNotifyChipConnectionClosed", "(I)V");
VerifyOrExit(method != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
VerifyOrExit(method != NULL, err = CHIP_JNI_ERROR_NO_ENV);

ChipLogProgress(Controller, "Calling Java NotifyChipConnectionClosed");

Expand All @@ -773,7 +774,7 @@ bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svc
const uint8_t * characteristicData, uint32_t characteristicDataLen)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jbyteArray svcIdObj;
jbyteArray charIdObj;
jbyteArray characteristicDataObj;
Expand All @@ -782,8 +783,7 @@ bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svc
bool rc = false;

ChipLogProgress(Controller, "Received SendCharacteristic");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);
Expand Down Expand Up @@ -822,16 +822,15 @@ bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svc
bool HandleSubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svcId, const uint8_t * charId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jbyteArray svcIdObj;
jbyteArray charIdObj;
jmethodID method;
intptr_t tmpConnObj;
bool rc = false;

ChipLogProgress(Controller, "Received SubscribeCharacteristic");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);
Expand Down Expand Up @@ -866,16 +865,15 @@ bool HandleSubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t
bool HandleUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t * svcId, const uint8_t * charId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jbyteArray svcIdObj;
jbyteArray charIdObj;
jmethodID method;
intptr_t tmpConnObj;
bool rc = false;

ChipLogProgress(Controller, "Received UnsubscribeCharacteristic");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

err = N2J_ByteArray(env, svcId, 16, svcIdObj);
SuccessOrExit(err);
Expand Down Expand Up @@ -910,14 +908,13 @@ bool HandleUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_
bool HandleCloseConnection(BLE_CONNECTION_OBJECT connObj)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jmethodID method;
intptr_t tmpConnObj;
bool rc = false;

ChipLogProgress(Controller, "Received CloseConnection");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

method = env->GetStaticMethodID(sAndroidChipStackCls, "onCloseConnection", "(I)Z");
VerifyOrExit(method != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
Expand Down Expand Up @@ -945,14 +942,13 @@ bool HandleCloseConnection(BLE_CONNECTION_OBJECT connObj)
uint16_t HandleGetMTU(BLE_CONNECTION_OBJECT connObj)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jmethodID method;
intptr_t tmpConnObj;
uint16_t mtu = 0;

ChipLogProgress(Controller, "Received GetMTU");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

{
AndroidDeviceControllerWrapper::StackUnlockGuard unlockGuard(&sStackLock);
Expand Down Expand Up @@ -981,15 +977,14 @@ uint16_t HandleGetMTU(BLE_CONNECTION_OBJECT connObj)
void HandleNewConnection(void * appState, const uint16_t discriminator)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env;
JNIEnv * env = GetEnvForCurrentThread();
jmethodID method;
jclass deviceControllerCls;
AndroidDeviceControllerWrapper * wrapper = reinterpret_cast<AndroidDeviceControllerWrapper *>(appState);
jobject self = wrapper->JavaObjectRef();

ChipLogProgress(Controller, "Received New Connection");

sJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);

deviceControllerCls = env->GetObjectClass(self);
VerifyOrExit(deviceControllerCls != NULL, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND);
Expand Down
2 changes: 2 additions & 0 deletions src/controller/java/CHIPJNIError.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@
#define CHIP_JNI_ERROR_TYPE_NOT_FOUND _CHIP_JNI_ERROR(1)
#define CHIP_JNI_ERROR_METHOD_NOT_FOUND _CHIP_JNI_ERROR(2)
#define CHIP_JNI_ERROR_FIELD_NOT_FOUND _CHIP_JNI_ERROR(3)
#define CHIP_JNI_ERROR_NO_ENV _CHIP_JNI_ERROR(4)
#define CHIP_JNI_ERROR_NULL_OBJECT _CHIP_JNI_ERROR(5)
67 changes: 67 additions & 0 deletions src/controller/java/JniReferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,37 @@

#include <support/CodeUtils.h>

void SetJavaVm(JavaVM * jvm)
{
sJvm = jvm;
}

JNIEnv * GetEnvForCurrentThread()
{
JNIEnv * env;
if (sJvm == NULL)
{
ChipLogError(Controller, "Missing Java VM");
return nullptr;
}
sJvm->GetEnv((void **) &env, JNI_VERSION_1_6);
if (env == NULL)
{
jint error;
#ifdef __ANDROID__
error = sJvm->AttachCurrentThreadAsDaemon(&env, NULL);
#else
error = sJvm->AttachCurrentThreadAsDaemon((void **) &env, NULL);
#endif
if (error != JNI_OK)
{
ChipLogError(Controller, "Failed to get JNIEnv for the current thread");
return nullptr;
}
}
return env;
}

CHIP_ERROR GetClassRef(JNIEnv * env, const char * clsType, jclass & outCls)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -36,3 +67,39 @@ CHIP_ERROR GetClassRef(JNIEnv * env, const char * clsType, jclass & outCls)
env->DeleteLocalRef(cls);
return err;
}

CHIP_ERROR FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature, jmethodID * methodId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
jclass javaClass = NULL;
VerifyOrExit(env != nullptr && object != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT);

javaClass = env->GetObjectClass(object);
ChipLogProgress(Controller, "FindMethod:: javaClass exists? %d", javaClass != NULL);
VerifyOrExit(javaClass != NULL, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND);

*methodId = env->GetMethodID(javaClass, methodName, methodSignature);
VerifyOrExit(*methodId != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);

exit:
ChipLogProgress(Controller, "FindMethod Returning %d", err);
return err;
}

void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument)
{
CHIP_ERROR err = CHIP_NO_ERROR;
jmethodID method;

err = FindMethod(env, object, methodName, "(I)V", &method);
SuccessOrExit(err);

env->ExceptionClear();
env->CallVoidMethod(object, method, argument);

exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Error calling Java method: %d", err);
}
}
9 changes: 9 additions & 0 deletions src/controller/java/JniReferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,13 @@

#include <core/CHIPError.h>

namespace {
JavaVM * sJvm = nullptr;
} // namespace

void SetJavaVm(JavaVM * jvm);
JNIEnv * GetEnvForCurrentThread();

CHIP_ERROR GetClassRef(JNIEnv * env, const char * clsType, jclass & outCls);
CHIP_ERROR FindMethod(JNIEnv * env, jobject object, const char * methodName, const char * methodSignature, jmethodID * methodId);
void CallVoidInt(JNIEnv * env, jobject object, const char * methodName, jint argument);

0 comments on commit aa96ea0

Please sign in to comment.