From e66ae201aa03488d5a04ffa3720c3555951be420 Mon Sep 17 00:00:00 2001 From: yunhanw-google Date: Mon, 26 Sep 2022 16:25:02 -0700 Subject: [PATCH] [Android] Integrate cluster state cache with android Java IM API (#22851) * Integrate cluster state cache with java im API * address comments --- src/app/ClusterStateCache.cpp | 5 ++ src/app/ClusterStateCache.h | 2 + src/controller/java/AndroidCallbacks.cpp | 46 +++++++++++++++++-- src/controller/java/AndroidCallbacks.h | 6 ++- .../java/CHIPDeviceController-JNI.cpp | 12 ++--- .../ChipDeviceController.java | 4 +- .../devicecontroller/model/ClusterState.java | 11 +++++ .../devicecontroller/model/NodeState.java | 10 ++++ 8 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/app/ClusterStateCache.cpp b/src/app/ClusterStateCache.cpp index acb6a0623db140..1ccff3e5567f67 100644 --- a/src/app/ClusterStateCache.cpp +++ b/src/app/ClusterStateCache.cpp @@ -532,5 +532,10 @@ CHIP_ERROR ClusterStateCache::OnUpdateDataVersionFilterList(DataVersionFilterIBs return err; } +CHIP_ERROR ClusterStateCache::GetLastReportDataPath(ConcreteClusterPath & aPath) +{ + aPath = mLastReportDataPath; + return CHIP_NO_ERROR; +} } // namespace app } // namespace chip diff --git a/src/app/ClusterStateCache.h b/src/app/ClusterStateCache.h index 8ba58f1d923798..c6c545e501a9da 100644 --- a/src/app/ClusterStateCache.h +++ b/src/app/ClusterStateCache.h @@ -483,6 +483,8 @@ class ClusterStateCache : protected ReadClient::Callback mEventStatusCache.clear(); } + CHIP_ERROR GetLastReportDataPath(ConcreteClusterPath & aPath); + private: using AttributeState = Variant, StatusIB>; // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for. diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp index 3fd3a42c0eb77f..b5d0cc58734c17 100644 --- a/src/controller/java/AndroidCallbacks.cpp +++ b/src/controller/java/AndroidCallbacks.cpp @@ -121,7 +121,7 @@ void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, con ReportCallback::ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, jobject reportCallback, jobject resubscriptionAttemptCallback) : - mBufferedReadAdapter(*this) + mClusterCacheAdapter(*this) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); @@ -186,6 +186,8 @@ void ReportCallback::OnReportBegin() void ReportCallback::OnReportEnd() { + UpdateClusterDataVersion(); + // Transform C++ jobject pair list to a Java HashMap, and call onReport() on the Java callback. CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -280,7 +282,43 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addAttribute method")); env->CallVoidMethod(mNodeStateObj, addAttributeMethod, static_cast(aPath.mEndpointId), static_cast(aPath.mClusterId), static_cast(aPath.mAttributeId), attributeStateObj); - VerifyOrReturnError(!env->ExceptionCheck(), env->ExceptionDescribe()); + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); + + UpdateClusterDataVersion(); +} + +void ReportCallback::UpdateClusterDataVersion() +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + chip::app::ConcreteClusterPath lastConcreteClusterPath; + + if (mClusterCacheAdapter.GetLastReportDataPath(lastConcreteClusterPath) != CHIP_NO_ERROR) + { + return; + } + + if (!lastConcreteClusterPath.IsValidConcreteClusterPath()) + { + return; + } + + chip::Optional committedDataVersion; + if (mClusterCacheAdapter.GetVersion(lastConcreteClusterPath, committedDataVersion) != CHIP_NO_ERROR) + { + return; + } + if (!committedDataVersion.HasValue()) + { + return; + } + + // SetDataVersion to NodeState + jmethodID setDataVersionMethod; + CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mNodeStateObj, "setDataVersion", "(IJI)V", &setDataVersionMethod); + VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find setDataVersion method")); + env->CallVoidMethod(mNodeStateObj, setDataVersionMethod, static_cast(lastConcreteClusterPath.mEndpointId), + static_cast(lastConcreteClusterPath.mClusterId), static_cast(committedDataVersion.Value())); + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLVReader * apData, const app::StatusIB * apStatus) @@ -356,7 +394,7 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV env->CallVoidMethod(mNodeStateObj, addEventMethod, static_cast(aEventHeader.mPath.mEndpointId), static_cast(aEventHeader.mPath.mClusterId), static_cast(aEventHeader.mPath.mEventId), eventStateObj); - VerifyOrReturnError(!env->ExceptionCheck(), env->ExceptionDescribe()); + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } CHIP_ERROR ReportCallback::CreateChipAttributePath(const app::ConcreteDataAttributePath & aPath, jobject & outObj) @@ -628,7 +666,7 @@ void ReportEventCallback::OnEventData(const app::EventHeader & aEventHeader, TLV env->CallVoidMethod(mNodeStateObj, addEventMethod, static_cast(aEventHeader.mPath.mEndpointId), static_cast(aEventHeader.mPath.mClusterId), static_cast(aEventHeader.mPath.mEventId), eventStateObj); - VerifyOrReturnError(!env->ExceptionCheck(), env->ExceptionDescribe()); + VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe()); } CHIP_ERROR ReportEventCallback::CreateChipEventPath(const app::ConcreteEventPath & aPath, jobject & outObj) diff --git a/src/controller/java/AndroidCallbacks.h b/src/controller/java/AndroidCallbacks.h index 684fd4c5487d44..915825aa8c4d83 100644 --- a/src/controller/java/AndroidCallbacks.h +++ b/src/controller/java/AndroidCallbacks.h @@ -42,7 +42,7 @@ struct GetConnectedDeviceCallback jobject mJavaCallbackRef = nullptr; }; -struct ReportCallback : public app::ReadClient::Callback +struct ReportCallback : public app::ClusterStateCache::Callback { /** Subscription established callback can be nullptr. */ ReportCallback(jobject wrapperCallback, jobject subscriptionEstablishedCallback, jobject reportCallback, @@ -74,9 +74,11 @@ struct ReportCallback : public app::ReadClient::Callback CHIP_ERROR CreateChipEventPath(const app::ConcreteEventPath & aPath, jobject & outObj); + void UpdateClusterDataVersion(); + app::ReadClient * mReadClient = nullptr; - app::BufferedReadCallback mBufferedReadAdapter; + app::ClusterStateCache mClusterCacheAdapter; jobject mWrapperCallbackRef = nullptr; jobject mSubscriptionEstablishedCallbackRef = nullptr; jobject mResubscriptionAttemptCallbackRef = nullptr; diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 21313a6c789e5f..2a4d7e9cc97755 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -1077,9 +1077,9 @@ JNI_METHOD(void, subscribe) auto callback = reinterpret_cast(callbackHandle); - app::ReadClient * readClient = - Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - callback->mBufferedReadAdapter, app::ReadClient::InteractionType::Subscribe); + app::ReadClient * readClient = Platform::New( + app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + callback->mClusterCacheAdapter.GetBufferedCallback(), app::ReadClient::InteractionType::Subscribe); err = readClient->SendRequest(params); if (err != CHIP_NO_ERROR) @@ -1126,9 +1126,9 @@ JNI_METHOD(void, read) auto callback = reinterpret_cast(callbackHandle); - app::ReadClient * readClient = - Platform::New(app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), - callback->mBufferedReadAdapter, app::ReadClient::InteractionType::Read); + app::ReadClient * readClient = Platform::New( + app::InteractionModelEngine::GetInstance(), device->GetExchangeManager(), + callback->mClusterCacheAdapter.GetBufferedCallback(), app::ReadClient::InteractionType::Read); err = readClient->SendRequest(params); if (err != CHIP_NO_ERROR) diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index 759dee577c502a..c24d0dd298dd4f 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -452,7 +452,7 @@ public byte[] getAttestationChallenge(long devicePtr) { } /** Subscribe to the given attribute path. */ - public void subscribeToPath( + public void subscribeToAttributePath( SubscriptionEstablishedCallback subscriptionEstablishedCallback, ReportCallback reportCallback, long devicePtr, @@ -524,7 +524,7 @@ public void subscribeToPath( } /** Read the given attribute path. */ - public void readPath( + public void readAttributePath( ReportCallback callback, long devicePtr, List attributePaths) { ReportCallbackJni jniCallback = new ReportCallbackJni(null, callback, null); read( diff --git a/src/controller/java/src/chip/devicecontroller/model/ClusterState.java b/src/controller/java/src/chip/devicecontroller/model/ClusterState.java index 149d3b1ca97662..e90d0e76acec54 100644 --- a/src/controller/java/src/chip/devicecontroller/model/ClusterState.java +++ b/src/controller/java/src/chip/devicecontroller/model/ClusterState.java @@ -19,15 +19,18 @@ import androidx.annotation.Nullable; import java.util.Map; +import java.util.Optional; /** Class for tracking CHIP cluster state in a hierarchical manner. */ public final class ClusterState { private Map attributes; private Map events; + private Optional dataVersion; public ClusterState(Map attributes, Map events) { this.attributes = attributes; this.events = events; + this.dataVersion = Optional.empty(); } public Map getAttributeStates() { @@ -38,6 +41,14 @@ public Map getEventStates() { return events; } + public void setDataVersion(int version) { + dataVersion = Optional.of(version); + } + + public Optional getDataVersion() { + return dataVersion; + } + /** * Convenience utility for getting an {@code AttributeState}. * diff --git a/src/controller/java/src/chip/devicecontroller/model/NodeState.java b/src/controller/java/src/chip/devicecontroller/model/NodeState.java index d2155aa1ff9b23..652dc3265ffab1 100644 --- a/src/controller/java/src/chip/devicecontroller/model/NodeState.java +++ b/src/controller/java/src/chip/devicecontroller/model/NodeState.java @@ -33,6 +33,16 @@ public Map getEndpointStates() { return endpoints; } + // Called from native code only, which ignores access modifiers. + private void setDataVersion(int endpointId, long clusterId, int dataVersion) { + EndpointState endpointState = getEndpointState(endpointId); + ClusterState clusterState = endpointState.getClusterState(clusterId); + + if (clusterState != null) { + clusterState.setDataVersion(dataVersion); + } + } + // Called from native code only, which ignores access modifiers. private void addAttribute( int endpointId, long clusterId, long attributeId, AttributeState attributeStateToAdd) {