diff --git a/examples/common/m5stack-tft/repo b/examples/common/m5stack-tft/repo index d99f5ef8df180a..a6299b6c7c0b2e 160000 --- a/examples/common/m5stack-tft/repo +++ b/examples/common/m5stack-tft/repo @@ -1 +1 @@ -Subproject commit d99f5ef8df180ab34b3d9fff6888d5bede7665c5 +Subproject commit a6299b6c7c0b2e3eb62fa08ee4bf7155c39bad1f diff --git a/examples/tv-app/android/App/content-app/src/main/AndroidManifest.xml b/examples/tv-app/android/App/content-app/src/main/AndroidManifest.xml index 61d036e0a90ef4..fff52c4b59db7e 100644 --- a/examples/tv-app/android/App/content-app/src/main/AndroidManifest.xml +++ b/examples/tv-app/android/App/content-app/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ - + diff --git a/examples/tv-app/android/java/AppImpl.cpp b/examples/tv-app/android/java/AppImpl.cpp index 4dfabd03f12ec6..c24e7e537dbb23 100644 --- a/examples/tv-app/android/java/AppImpl.cpp +++ b/examples/tv-app/android/java/AppImpl.cpp @@ -355,6 +355,87 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vend return nullptr; } +class DevicePairedCommand : public Controller::DevicePairingDelegate +{ +public: + struct CallbackContext + { + uint16_t vendorId; + uint16_t productId; + chip::NodeId nodeId; + + CallbackContext(uint16_t vId, uint16_t pId, chip::NodeId nId) : vendorId(vId), productId(pId), nodeId(nId) {} + }; + DevicePairedCommand(uint16_t vendorId, uint16_t productId, chip::NodeId nodeId) : + mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this) + { + mContext = std::make_shared(vendorId, productId, nodeId); + } + + static void OnDeviceConnectedFn(void * context, chip::Messaging::ExchangeManager & exchangeMgr, + const chip::SessionHandle & sessionHandle) + { + auto * pairingCommand = static_cast(context); + auto cbContext = pairingCommand->mContext; + + if (pairingCommand) + { + ChipLogProgress(DeviceLayer, + "OnDeviceConnectedFn - Updating ACL for node id: " ChipLogFormatX64 + " and vendor id: %d and product id: %d", + ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId); + + GetCommissionerDiscoveryController()->CommissioningSucceeded(cbContext->vendorId, cbContext->productId, + cbContext->nodeId, exchangeMgr, sessionHandle); + } + } + + static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error) + { + auto * pairingCommand = static_cast(context); + auto cbContext = pairingCommand->mContext; + + if (pairingCommand) + { + ChipLogProgress(DeviceLayer, + "OnDeviceConnectionFailureFn - Not updating ACL for node id: " ChipLogFormatX64 + " and vendor id: %d and product id: %d", + ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId); + // TODO: Remove Node Id + } + } + + chip::Callback::Callback mOnDeviceConnectedCallback; + chip::Callback::Callback mOnDeviceConnectionFailureCallback; + std::shared_ptr mContext; +}; + +void refreshConnectedClientsAcl(uint16_t vendorId, uint16_t productId, ContentAppImpl * app) +{ + + std::set nodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForContentApp(vendorId, productId); + + for (const auto & allowedVendor : app->GetApplicationBasicDelegate()->GetAllowedVendorList()) + { + std::set tempNodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForAllowVendorId(allowedVendor); + + nodeIds.insert(tempNodeIds.begin(), tempNodeIds.end()); + } + + for (const auto & nodeId : nodeIds) + { + + ChipLogProgress(DeviceLayer, + "Creating Pairing Command with node id: " ChipLogFormatX64 " and vendor id: %d and product id: %d", + ChipLogValueX64(nodeId), vendorId, productId); + + std::shared_ptr pairingCommand = std::make_shared(vendorId, productId, nodeId); + + GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback, + &pairingCommand->mOnDeviceConnectionFailureCallback); + } +} + EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, const char * szApplicationVersion, std::vector supportedClusters, jobject manager) @@ -369,6 +450,9 @@ EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint1 app->GetEndpointId()); mContentApps.push_back(app); mDataVersions.push_back(dataVersionBuf); + + refreshConnectedClientsAcl(vendorId, productId, app); + return epId; } @@ -387,6 +471,9 @@ EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint1 app->GetEndpointId()); mContentApps.push_back(app); mDataVersions.push_back(dataVersionBuf); + + refreshConnectedClientsAcl(vendorId, productId, app); + return epId; } diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 04b5f4199edcaa..65a0a4409e9b8f 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -258,6 +258,8 @@ class MyPostCommissioningListener : public PostCommissioningListener // read current binding list chip::Controller::ClusterBase cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId); + ContentAppPlatform::GetInstance().StoreNodeIdForContentApp(vendorId, productId, nodeId); + cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle); CHIP_ERROR err = diff --git a/examples/tv-app/linux/main.cpp b/examples/tv-app/linux/main.cpp index 29fdd69cb36792..c2055e0abd03f3 100644 --- a/examples/tv-app/linux/main.cpp +++ b/examples/tv-app/linux/main.cpp @@ -45,6 +45,31 @@ void ApplicationInit() ChipLogDetail(DeviceLayer, "TV Linux App: Warning - Fixed Content App Endpoint Not Disabled"); // Can't disable this without breaking CI unit tests that act upon account login cluster (only available on ep3) // emberAfEndpointEnableDisable(3, false); + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + // Install Content Apps + ContentAppFactoryImpl * factory = GetContentAppFactoryImpl(); + + // Content App 1 + constexpr uint16_t kApp1VendorId = 65521; + constexpr uint16_t kApp1ProductId = 32769; + factory->InstallContentApp(kApp1VendorId, kApp1ProductId); + + // Content App 2 + constexpr uint16_t kApp2VendorId = 1; + constexpr uint16_t kApp2ProductId = 11; + factory->InstallContentApp(kApp2VendorId, kApp2ProductId); + + // Content App 3 + constexpr uint16_t kApp3VendorId = 9050; + constexpr uint16_t kApp3ProductId = 22; + factory->InstallContentApp(kApp3VendorId, kApp3ProductId); + + // Content App 4 + constexpr uint16_t kApp4VendorId = 1111; + constexpr uint16_t kApp4ProductId = 22; + factory->InstallContentApp(kApp4VendorId, kApp4ProductId); +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED } void ApplicationShutdown() {} diff --git a/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp b/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp index b39e84ad40f89a..5125ebbbbd7ecd 100644 --- a/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp +++ b/examples/tv-app/tv-common/shell/AppTvShellCommands.cpp @@ -209,6 +209,10 @@ static CHIP_ERROR PrintAllCommands() #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE streamer_printf(sout, " print-app-access Print all ACLs for app platform fabric. Usage: app print-app-access\r\n"); streamer_printf(sout, " remove-app-access Remove all ACLs for app platform fabric. Usage: app remove-app-access\r\n"); + streamer_printf( + sout, + " print-installed-apps Print all installed content apps with their endpoints. Usage: app print-installed-apps\r\n"); + streamer_printf(sout, " commission Commission given udc-entry using given pincode from corresponding app. Usage: " "app commission 0\r\n"); @@ -436,6 +440,13 @@ static CHIP_ERROR AppPlatformHandler(int argc, char ** argv) Access::GetAccessControl().DeleteAllEntriesForFabric(GetDeviceCommissioner()->GetFabricIndex()); return CHIP_NO_ERROR; } + else if (strcmp(argv[0], "print-installed-apps") == 0) + { + ContentAppFactoryImpl * factory = GetContentAppFactoryImpl(); + factory->LogInstalledApps(); + + return CHIP_NO_ERROR; + } else if (strcmp(argv[0], "commission") == 0) { if (argc < 2) diff --git a/examples/tv-app/tv-common/src/AppTv.cpp b/examples/tv-app/tv-common/src/AppTv.cpp index 03422c3fa462e7..8d81d9cf6c2c5c 100644 --- a/examples/tv-app/tv-common/src/AppTv.cpp +++ b/examples/tv-app/tv-common/src/AppTv.cpp @@ -164,6 +164,8 @@ class MyPostCommissioningListener : public PostCommissioningListener // read current binding list chip::Controller::ClusterBase cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId); + ContentAppPlatform::GetInstance().StoreNodeIdForContentApp(vendorId, productId, nodeId); + cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle); CHIP_ERROR err = @@ -565,6 +567,63 @@ void ContentAppFactoryImpl::AddAdminVendorId(uint16_t vendorId) mAdminVendorIds.push_back(vendorId); } +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE +class DevicePairedCommand : public Controller::DevicePairingDelegate +{ +public: + struct CallbackContext + { + uint16_t vendorId; + uint16_t productId; + chip::NodeId nodeId; + + CallbackContext(uint16_t vId, uint16_t pId, chip::NodeId nId) : vendorId(vId), productId(pId), nodeId(nId) {} + }; + DevicePairedCommand(uint16_t vendorId, uint16_t productId, chip::NodeId nodeId) : + mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this) + { + mContext = std::make_shared(vendorId, productId, nodeId); + } + + static void OnDeviceConnectedFn(void * context, chip::Messaging::ExchangeManager & exchangeMgr, + const chip::SessionHandle & sessionHandle) + { + auto * pairingCommand = static_cast(context); + auto cbContext = pairingCommand->mContext; + + if (pairingCommand) + { + ChipLogProgress(DeviceLayer, + "OnDeviceConnectedFn - Updating ACL for node id: " ChipLogFormatX64 + " and vendor id: %d and product id: %d", + ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId); + + GetCommissionerDiscoveryController()->CommissioningSucceeded(cbContext->vendorId, cbContext->productId, + cbContext->nodeId, exchangeMgr, sessionHandle); + } + } + + static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error) + { + auto * pairingCommand = static_cast(context); + auto cbContext = pairingCommand->mContext; + + if (pairingCommand) + { + ChipLogProgress(DeviceLayer, + "OnDeviceConnectionFailureFn - Not updating ACL for node id: " ChipLogFormatX64 + " and vendor id: %d and product id: %d", + ChipLogValueX64(cbContext->nodeId), cbContext->vendorId, cbContext->productId); + // TODO: Remove Node Id + } + } + + chip::Callback::Callback mOnDeviceConnectedCallback; + chip::Callback::Callback mOnDeviceConnectionFailureCallback; + std::shared_ptr mContext; +}; +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + void ContentAppFactoryImpl::InstallContentApp(uint16_t vendorId, uint16_t productId) { auto make_default_supported_clusters = []() { @@ -605,6 +664,46 @@ void ContentAppFactoryImpl::InstallContentApp(uint16_t vendorId, uint16_t produc make_default_supported_clusters()); mContentApps.emplace_back(std::move(ptr)); } + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + // Get the list of node ids + std::set nodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForContentApp(vendorId, productId); + + // update ACLs + for (auto & contentApp : mContentApps) + { + auto app = contentApp.get(); + + if (app->MatchesPidVid(productId, vendorId)) + { + CatalogVendorApp vendorApp = app->GetApplicationBasicDelegate()->GetCatalogVendorApp(); + + GetContentAppFactoryImpl()->LoadContentApp(vendorApp); + } + + // update the list of node ids with content apps allowed vendor list + for (const auto & allowedVendor : app->GetApplicationBasicDelegate()->GetAllowedVendorList()) + { + std::set tempNodeIds = ContentAppPlatform::GetInstance().GetNodeIdsForAllowVendorId(allowedVendor); + + nodeIds.insert(tempNodeIds.begin(), tempNodeIds.end()); + } + } + + // refresh ACLs + for (const auto & nodeId : nodeIds) + { + + ChipLogProgress(DeviceLayer, + "Creating Pairing Command with node id: " ChipLogFormatX64 " and vendor id: %d and product id: %d", + ChipLogValueX64(nodeId), vendorId, productId); + + std::shared_ptr pairingCommand = std::make_shared(vendorId, productId, nodeId); + + GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback, + &pairingCommand->mOnDeviceConnectionFailureCallback); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE } bool ContentAppFactoryImpl::UninstallContentApp(uint16_t vendorId, uint16_t productId) @@ -625,8 +724,9 @@ bool ContentAppFactoryImpl::UninstallContentApp(uint16_t vendorId, uint16_t prod ChipLogProgress(DeviceLayer, "Found an app vid=%d pid=%d. Uninstalling it.", app->GetApplicationBasicDelegate()->HandleGetVendorId(), app->GetApplicationBasicDelegate()->HandleGetProductId()); + EndpointId removedEndpointID = ContentAppPlatform::GetInstance().RemoveContentApp(app); + ChipLogProgress(DeviceLayer, "Removed content app at endpoint id: %d", removedEndpointID); mContentApps.erase(mContentApps.begin() + index); - // TODO: call ContentAppPlatform->RemoveContentApp(ids...) return true; } @@ -701,22 +801,8 @@ std::list ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoi CHIP_ERROR AppTvInit() { #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - // test data for apps - constexpr uint16_t kApp1VendorId = 1; - constexpr uint16_t kApp1ProductId = 11; - constexpr uint16_t kApp2VendorId = 65521; - constexpr uint16_t kApp2ProductId = 32769; - constexpr uint16_t kApp3VendorId = 9050; - constexpr uint16_t kApp3ProductId = 22; - constexpr uint16_t kApp4VendorId = 1111; - constexpr uint16_t kApp4ProductId = 22; - ContentAppPlatform::GetInstance().SetupAppPlatform(); ContentAppPlatform::GetInstance().SetContentAppFactory(&gFactory); - gFactory.InstallContentApp(kApp1VendorId, kApp1ProductId); - gFactory.InstallContentApp(kApp2VendorId, kApp2ProductId); - gFactory.InstallContentApp(kApp3VendorId, kApp3ProductId); - gFactory.InstallContentApp(kApp4VendorId, kApp4ProductId); uint16_t value; if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(value) != CHIP_NO_ERROR) { diff --git a/src/app/app-platform/ContentAppPlatform.cpp b/src/app/app-platform/ContentAppPlatform.cpp index fb2d6ab39a1b5f..214af261e26e54 100644 --- a/src/app/app-platform/ContentAppPlatform.cpp +++ b/src/app/app-platform/ContentAppPlatform.cpp @@ -387,6 +387,57 @@ ContentApp * ContentAppPlatform::GetContentApp(EndpointId id) return nullptr; } +// create a string key from vendorId and productId +std::string createKey(uint16_t vendorId, uint16_t productId) +{ + return std::to_string(vendorId) + ":" + std::to_string(productId); +} + +void ContentAppPlatform::StoreNodeIdForContentApp(uint16_t vendorId, uint16_t productId, NodeId nodeId) +{ + std::string key = createKey(vendorId, productId); + + ChipLogProgress(DeviceLayer, "Stored node id: " ChipLogFormatX64 " for key: %s", ChipLogValueX64(nodeId), key.c_str()); + + mConnectedContentAppNodeIds[key].insert(nodeId); +} + +std::set ContentAppPlatform::GetNodeIdsForContentApp(uint16_t vendorId, uint16_t productId) +{ + std::string key = createKey(vendorId, productId); + + ChipLogProgress(DeviceLayer, "Retrieving node id for key: %s", key.c_str()); + + auto it = mConnectedContentAppNodeIds.find(key); + if (it != mConnectedContentAppNodeIds.end()) + { + ChipLogProgress(DeviceLayer, "Found node id"); + return it->second; + } + + ChipLogProgress(DeviceLayer, "Didn't find node id"); + // If key not found, return an empty set + return {}; +} + +std::set ContentAppPlatform::GetNodeIdsForAllowVendorId(uint16_t vendorId) +{ + std::set result; + std::string vendorPrefix = std::to_string(vendorId) + ":"; + + for (const auto & pair : mConnectedContentAppNodeIds) + { + const std::string & key = pair.first; + if (key.find(vendorPrefix) == 0) + { // Check if the key starts with the vendor prefix + const std::set & nodeIds = pair.second; + result.insert(nodeIds.begin(), nodeIds.end()); + } + } + + return result; +} + void ContentAppPlatform::SetCurrentApp(ContentApp * app) { if (!HasCurrentApp()) diff --git a/src/app/app-platform/ContentAppPlatform.h b/src/app/app-platform/ContentAppPlatform.h index 16a47c26a3b991..45615d09ed8ddf 100644 --- a/src/app/app-platform/ContentAppPlatform.h +++ b/src/app/app-platform/ContentAppPlatform.h @@ -161,6 +161,18 @@ class DLL_EXPORT ContentAppPlatform bool HasTargetContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId, Protocols::UserDirectedCommissioning::TargetAppInfo & info, uint32_t & passcode); + // returns set of connected nodes for a given content app + std::set GetNodeIdsForContentApp(uint16_t vendorId, uint16_t productId); + + // returns set of connected nodes for a given allowed vendor id + std::set GetNodeIdsForAllowVendorId(uint16_t vendorId); + + // store node id for content app after commissioning + // node id can be used later on to update ACL + // in case app is not installed + // Note: This is in memory storing, the values are deleted after reboot + void StoreNodeIdForContentApp(uint16_t vendorId, uint16_t productId, NodeId nodeId); + /** * @brief * Add ACLs on this device for the given client, @@ -201,6 +213,8 @@ class DLL_EXPORT ContentAppPlatform EndpointId mCurrentEndpointId; EndpointId mFirstDynamicEndpointId; ContentApp * mContentApps[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT]; + // key is string -> vendorId:producTid + std::map> mConnectedContentAppNodeIds; private: void IncrementCurrentEndpointID();