Skip to content

Commit

Permalink
Fix the local reference leaks for attribute and event path (#29175)
Browse files Browse the repository at this point in the history
  • Loading branch information
yunhanw-google authored Sep 13, 2023
1 parent d453502 commit 6c09e34
Showing 1 changed file with 93 additions and 72 deletions.
165 changes: 93 additions & 72 deletions src/controller/java/AndroidCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,67 @@ static const int MILLIS_SINCE_EPOCH = 1;
// Add the bytes for attribute tag(1:control + 8:tag + 8:length) and structure(1:struct + 1:close container)
static const int EXTRA_SPACE_FOR_ATTRIBUTE_TAG = 19;

class JniChipAttributePath
{
public:
JniChipAttributePath(JNIEnv * env, const app::ConcreteDataAttributePath & aPath) : mEnv(env)
{
jclass attributePathCls = nullptr;
ReturnOnFailure(mError = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/model/ChipAttributePath",
attributePathCls));
JniClass attributePathJniCls(attributePathCls);

jmethodID attributePathCtor =
env->GetStaticMethodID(attributePathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipAttributePath;");
VerifyOrReturn(attributePathCtor != nullptr, mError = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
mData = env->CallStaticObjectMethod(attributePathCls, attributePathCtor, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mAttributeId));
VerifyOrReturn(mData != nullptr, mError = CHIP_JNI_ERROR_NULL_OBJECT);
return;
}

~JniChipAttributePath() { mEnv->DeleteLocalRef(mData); }

CHIP_ERROR GetError() { return mError; }
jobject GetData() { return mData; }

private:
JNIEnv * mEnv = nullptr;
jobject mData = nullptr;
CHIP_ERROR mError = CHIP_NO_ERROR;
};

class JniChipEventPath
{
public:
JniChipEventPath(JNIEnv * env, const app::ConcreteEventPath & aPath) : mEnv(env)
{
jclass eventPathCls = nullptr;
ReturnOnFailure(
mError = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/model/ChipEventPath", eventPathCls));
JniClass eventPathJniCls(eventPathCls);

jmethodID eventPathCtor =
env->GetStaticMethodID(eventPathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipEventPath;");
VerifyOrReturn(eventPathCtor != nullptr, mError = CHIP_JNI_ERROR_METHOD_NOT_FOUND);

mData = env->CallStaticObjectMethod(eventPathCls, eventPathCtor, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mEventId));
VerifyOrReturn(mData != nullptr, mError = CHIP_JNI_ERROR_NULL_OBJECT);
return;
}

~JniChipEventPath() { mEnv->DeleteLocalRef(mData); }

CHIP_ERROR GetError() { return mError; }
jobject GetData() { return mData; }

private:
JNIEnv * mEnv = nullptr;
jobject mData = nullptr;
CHIP_ERROR mError = CHIP_NO_ERROR;
};

GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback) :
mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this)
{
Expand Down Expand Up @@ -254,27 +315,27 @@ CHIP_ERROR ConvertReportTlvToJson(const uint32_t id, TLV::TLVReader & data, std:
void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
const app::StatusIB & aStatus)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
jobject attributePathObj = nullptr;
err = CreateChipAttributePath(aPath, attributePathObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
JniChipAttributePath attributePathObj(env, aPath);
VerifyOrReturn(attributePathObj.GetError() == CHIP_NO_ERROR,
ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));

if (aPath.IsListItemOperation())
{
ReportError(attributePathObj, nullptr, CHIP_ERROR_INCORRECT_STATE);
ReportError(attributePathObj.GetData(), nullptr, CHIP_ERROR_INCORRECT_STATE);
return;
}

if (aStatus.mStatus != Protocols::InteractionModel::Status::Success)
{
ReportError(attributePathObj, nullptr, aStatus.mStatus);
ReportError(attributePathObj.GetData(), nullptr, aStatus.mStatus);
return;
}

if (apData == nullptr)
{
ReportError(attributePathObj, nullptr, CHIP_ERROR_INVALID_ARGUMENT);
ReportError(attributePathObj.GetData(), nullptr, CHIP_ERROR_INVALID_ARGUMENT);
return;
}

Expand All @@ -293,9 +354,9 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
err = CHIP_NO_ERROR;
}

VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj, nullptr, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj.GetData(), nullptr, err));
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe(),
ReportError(attributePathObj, nullptr, CHIP_JNI_ERROR_EXCEPTION_THROWN));
ReportError(attributePathObj.GetData(), nullptr, CHIP_JNI_ERROR_EXCEPTION_THROWN));
#endif
// Create TLV byte array to pass to Java layer
size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead();
Expand All @@ -308,14 +369,14 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
TLV::TLVWriter writer;
writer.Init(buffer.get(), bufferLen);
err = writer.CopyElement(TLV::AnonymousTag(), readerForJavaTLV);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj, nullptr, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj.GetData(), nullptr, err));
size = writer.GetLengthWritten();
chip::ByteArray jniByteArray(env, reinterpret_cast<jbyte *>(buffer.get()), size);

// Convert TLV to JSON
std::string json;
err = ConvertReportTlvToJson(static_cast<uint32_t>(aPath.mAttributeId), *apData, json);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj, nullptr, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj.GetData(), nullptr, err));
UtfString jsonString(env, json.c_str());

// Create AttributeState object
Expand All @@ -338,6 +399,7 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
env->CallVoidMethod(mNodeStateObj, addAttributeMethod, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mAttributeId), attributeStateObj);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
env->DeleteLocalRef(attributeStateObj);

UpdateClusterDataVersion();
}
Expand Down Expand Up @@ -378,15 +440,15 @@ void ReportCallback::UpdateClusterDataVersion()

void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLVReader * apData, const app::StatusIB * apStatus)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
jobject eventPathObj = nullptr;
err = CreateChipEventPath(aEventHeader.mPath, eventPathObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipEventPath: %s", ErrorStr(err)));
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
JniChipEventPath eventPathObj(env, aEventHeader.mPath);
VerifyOrReturn(eventPathObj.GetError() == CHIP_NO_ERROR,
ChipLogError(Controller, "Unable to create Java ChipEventPath: %s", ErrorStr(err)));

if (apData == nullptr)
{
ReportError(nullptr, eventPathObj, CHIP_ERROR_INVALID_ARGUMENT);
ReportError(nullptr, eventPathObj.GetData(), CHIP_ERROR_INVALID_ARGUMENT);
return;
}

Expand All @@ -409,7 +471,7 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
else
{
ChipLogError(Controller, "Unsupported event timestamp type");
ReportError(nullptr, eventPathObj, CHIP_ERROR_INVALID_ARGUMENT);
ReportError(nullptr, eventPathObj.GetData(), CHIP_ERROR_INVALID_ARGUMENT);
return;
}

Expand All @@ -423,9 +485,9 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
{
err = CHIP_NO_ERROR;
}
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(nullptr, eventPathObj, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(nullptr, eventPathObj.GetData(), err));
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe(),
ReportError(nullptr, eventPathObj, CHIP_JNI_ERROR_EXCEPTION_THROWN));
ReportError(nullptr, eventPathObj.GetData(), CHIP_JNI_ERROR_EXCEPTION_THROWN));
#endif

// Create TLV byte array to pass to Java layer
Expand All @@ -438,14 +500,14 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
TLV::TLVWriter writer;
writer.Init(buffer.get(), bufferLen);
err = writer.CopyElement(TLV::AnonymousTag(), readerForJavaTLV);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(nullptr, eventPathObj, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(nullptr, eventPathObj.GetData(), err));
size = writer.GetLengthWritten();
chip::ByteArray jniByteArray(env, reinterpret_cast<jbyte *>(buffer.get()), size);

// Convert TLV to JSON
std::string json;
err = ConvertReportTlvToJson(static_cast<uint32_t>(aEventHeader.mPath.mEventId), *apData, json);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(eventPathObj, nullptr, err));
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(eventPathObj.GetData(), nullptr, err));
UtfString jsonString(env, json.c_str());

// Create EventState object
Expand All @@ -469,27 +531,7 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
static_cast<jlong>(aEventHeader.mPath.mClusterId), static_cast<jlong>(aEventHeader.mPath.mEventId),
eventStateObj);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

CHIP_ERROR CreateChipAttributePath(const app::ConcreteDataAttributePath & aPath, jobject & outObj)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
CHIP_ERROR err = CHIP_NO_ERROR;

jclass attributePathCls = nullptr;
err = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/model/ChipAttributePath", attributePathCls);
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
JniClass attributePathJniCls(attributePathCls);

jmethodID attributePathCtor =
env->GetStaticMethodID(attributePathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipAttributePath;");
VerifyOrReturnError(attributePathCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);

outObj = env->CallStaticObjectMethod(attributePathCls, attributePathCtor, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mAttributeId));
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT);

return err;
env->DeleteLocalRef(eventStateObj);
}

CHIP_ERROR InvokeCallback::CreateInvokeElement(const app::ConcreteCommandPath & aPath, TLV::TLVReader * apData, jobject & outObj)
Expand Down Expand Up @@ -549,27 +591,6 @@ CHIP_ERROR InvokeCallback::CreateInvokeElement(const app::ConcreteCommandPath &
return err;
}

CHIP_ERROR ReportCallback::CreateChipEventPath(const app::ConcreteEventPath & aPath, jobject & outObj)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
CHIP_ERROR err = CHIP_NO_ERROR;

jclass eventPathCls = nullptr;
err = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/model/ChipEventPath", eventPathCls);
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
JniClass eventPathJniCls(eventPathCls);

jmethodID eventPathCtor =
env->GetStaticMethodID(eventPathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipEventPath;");
VerifyOrReturnError(eventPathCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);

outObj = env->CallStaticObjectMethod(eventPathCls, eventPathCtor, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mEventId));
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT);

return err;
}

void ReportCallback::OnError(CHIP_ERROR aError)
{
ReportError(nullptr, nullptr, aError);
Expand Down Expand Up @@ -690,15 +711,15 @@ WriteAttributesCallback::~WriteAttributesCallback()
void WriteAttributesCallback::OnResponse(const app::WriteClient * apWriteClient, const app::ConcreteDataAttributePath & aPath,
app::StatusIB aStatus)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
jobject attributePathObj = nullptr;
err = CreateChipAttributePath(aPath, attributePathObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
JniChipAttributePath attributePathObj(env, aPath);
VerifyOrReturn(attributePathObj.GetError() == CHIP_NO_ERROR,
ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));

if (aStatus.mStatus != Protocols::InteractionModel::Status::Success)
{
ReportError(attributePathObj, aStatus.mStatus);
ReportError(attributePathObj.GetData(), aStatus.mStatus);
return;
}

Expand All @@ -708,7 +729,7 @@ void WriteAttributesCallback::OnResponse(const app::WriteClient * apWriteClient,
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err)));

DeviceLayer::StackUnlock unlock;
env->CallVoidMethod(mJavaCallbackRef, onResponseMethod, attributePathObj);
env->CallVoidMethod(mJavaCallbackRef, onResponseMethod, attributePathObj.GetData());
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

Expand Down

0 comments on commit 6c09e34

Please sign in to comment.