LCOV - code coverage report
Current view: top level - app/reporting - Engine.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 10 10 100.0 %
Date: 2024-02-15 08:20:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *      This file defines Reporting Engine for a CHIP Interaction Model
      22             :  *
      23             :  */
      24             : 
      25             : #pragma once
      26             : 
      27             : #include <access/AccessControl.h>
      28             : #include <app/MessageDef/ReportDataMessage.h>
      29             : #include <app/ReadHandler.h>
      30             : #include <app/util/basic-types.h>
      31             : #include <lib/core/CHIPCore.h>
      32             : #include <lib/support/CodeUtils.h>
      33             : #include <lib/support/logging/CHIPLogging.h>
      34             : #include <messaging/ExchangeContext.h>
      35             : #include <messaging/ExchangeMgr.h>
      36             : #include <protocols/Protocols.h>
      37             : #include <system/SystemPacketBuffer.h>
      38             : #include <system/TLVPacketBufferBackingStore.h>
      39             : 
      40             : namespace chip {
      41             : namespace app {
      42             : 
      43             : class InteractionModelEngine;
      44             : class TestReadInteraction;
      45             : 
      46             : namespace reporting {
      47             : /*
      48             :  *  @class Engine
      49             :  *
      50             :  *  @brief The reporting engine is responsible for generating reports to reader. It is able to find the intersection
      51             :  * between the path interest set of each reader with what has changed in the publisher data store and generate tailored
      52             :  * reports for each reader.
      53             :  *
      54             :  *         At its core, it  tries to gather and pack as much relevant attributes changes and/or events as possible into a report
      55             :  * message before sending that to the reader. It continues to do so until it has no more work to do.
      56             :  */
      57             : class Engine
      58             : {
      59             : public:
      60             :     /**
      61             :      *  Constructor Engine with a valid InteractionModelEngine pointer.
      62             :      */
      63             :     Engine(InteractionModelEngine * apImEngine);
      64             : 
      65             :     /**
      66             :      * Initializes the reporting engine. Should only be called once.
      67             :      *
      68             :      * @retval #CHIP_NO_ERROR On success.
      69             :      * @retval other           Was unable to retrieve data and write it into the writer.
      70             :      */
      71             :     CHIP_ERROR Init();
      72             : 
      73             :     void Shutdown();
      74             : 
      75             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
      76             :     void SetWriterReserved(uint32_t aReservedSize) { mReservedSize = aReservedSize; }
      77             : 
      78             :     void SetMaxAttributesPerChunk(uint32_t aMaxAttributesPerChunk) { mMaxAttributesPerChunk = aMaxAttributesPerChunk; }
      79             : #endif
      80             : 
      81             :     /**
      82             :      * Should be invoked when the device receives a Status report, or when the Report data request times out.
      83             :      * This allows the engine to do some clean-up.
      84             :      *
      85             :      */
      86             :     void OnReportConfirm();
      87             : 
      88             :     /**
      89             :      * Main work-horse function that executes the run-loop asynchronously on the CHIP thread
      90             :      */
      91             :     CHIP_ERROR ScheduleRun();
      92             : 
      93             :     /**
      94             :      * Application marks mutated change path and would be sent out in later report.
      95             :      */
      96             :     CHIP_ERROR SetDirty(AttributePathParams & aAttributePathParams);
      97             : 
      98             :     /**
      99             :      * @brief
     100             :      *  Schedule the event delivery
     101             :      *
     102             :      */
     103             :     CHIP_ERROR ScheduleEventDelivery(ConcreteEventPath & aPath, uint32_t aBytesWritten);
     104             : 
     105             :     /*
     106             :      * Resets the tracker that tracks the currently serviced read handler.
     107             :      * apReadHandler can be non-null to indicate that the reset is due to a
     108             :      * specific ReadHandler being deallocated.
     109             :      */
     110         727 :     void ResetReadHandlerTracker(ReadHandler * apReadHandlerBeingDeleted)
     111             :     {
     112         727 :         if (apReadHandlerBeingDeleted == mRunningReadHandler)
     113             :         {
     114             :             // Just decrement, so our increment after we finish running it will
     115             :             // do the right thing.
     116         667 :             --mCurReadHandlerIdx;
     117             :         }
     118             :         else
     119             :         {
     120             :             // No idea what to do here to make the indexing sane.  Just start at
     121             :             // the beginning.  We need to do better here; see
     122             :             // https://github.com/project-chip/connectedhomeip/issues/13809
     123          60 :             mCurReadHandlerIdx = 0;
     124             :         }
     125         727 :     }
     126             : 
     127             :     uint32_t GetNumReportsInFlight() const { return mNumReportsInFlight; }
     128             : 
     129        2497 :     uint64_t GetDirtySetGeneration() const { return mDirtyGeneration; }
     130             : 
     131             :     /**
     132             :      * Schedule event delivery to happen immediately and run reporting to get
     133             :      * those reports into messages and on the wire.  This can be done either for
     134             :      * a specific fabric, identified by the provided FabricIndex, or across all
     135             :      * fabrics if no FabricIndex is provided.
     136             :      */
     137             :     void ScheduleUrgentEventDeliverySync(Optional<FabricIndex> fabricIndex = NullOptional);
     138             : 
     139             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     140             :     size_t GetGlobalDirtySetSize() { return mGlobalDirtySet.Allocated(); }
     141             : #endif
     142             : 
     143             : private:
     144             :     /**
     145             :      * Main work-horse function that executes the run-loop.
     146             :      */
     147             :     void Run();
     148             : 
     149             :     friend class TestReportingEngine;
     150             :     friend class ::chip::app::TestReadInteraction;
     151             : 
     152        1783 :     bool IsRunScheduled() const { return mRunScheduled; }
     153             : 
     154             :     struct AttributePathParamsWithGeneration : public AttributePathParams
     155             :     {
     156          77 :         AttributePathParamsWithGeneration() {}
     157          77 :         AttributePathParamsWithGeneration(const AttributePathParams aPath) : AttributePathParams(aPath) {}
     158             :         uint64_t mGeneration = 0;
     159             :     };
     160             : 
     161             :     /**
     162             :      * Build Single Report Data including attribute changes and event data stream, and send out
     163             :      *
     164             :      */
     165             :     CHIP_ERROR BuildAndSendSingleReportData(ReadHandler * apReadHandler);
     166             : 
     167             :     CHIP_ERROR BuildSingleReportDataAttributeReportIBs(ReportDataMessage::Builder & reportDataBuilder, ReadHandler * apReadHandler,
     168             :                                                        bool * apHasMoreChunks, bool * apHasEncodedData);
     169             :     CHIP_ERROR BuildSingleReportDataEventReports(ReportDataMessage::Builder & reportDataBuilder, ReadHandler * apReadHandler,
     170             :                                                  bool aBufferIsUsed, bool * apHasMoreChunks, bool * apHasEncodedData);
     171             :     CHIP_ERROR RetrieveClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
     172             :                                    AttributeReportIBs::Builder & aAttributeReportIBs,
     173             :                                    const ConcreteReadAttributePath & aClusterInfo,
     174             :                                    AttributeValueEncoder::AttributeEncodeState * apEncoderState);
     175             :     CHIP_ERROR CheckAccessDeniedEventPaths(TLV::TLVWriter & aWriter, bool & aHasEncodedData, ReadHandler * apReadHandler);
     176             : 
     177             :     // If version match, it means don't send, if version mismatch, it means send.
     178             :     // If client sends the same path with multiple data versions, client will get the data back per the spec, because at least one
     179             :     // of those will fail to match.  This function should return false if either nothing in the list matches the given
     180             :     // endpoint+cluster in the path or there is an entry in the list that matches the endpoint+cluster in the path but does not
     181             :     // match the current data version of that cluster.
     182             :     bool IsClusterDataVersionMatch(const ObjectList<DataVersionFilter> * aDataVersionFilterList,
     183             :                                    const ConcreteReadAttributePath & aPath);
     184             : 
     185             :     /**
     186             :      * Send Report via ReadHandler
     187             :      *
     188             :      */
     189             :     CHIP_ERROR SendReport(ReadHandler * apReadHandler, System::PacketBufferHandle && aPayload, bool aHasMoreChunks);
     190             : 
     191             :     /**
     192             :      * Generate and send the report data request when there exists subscription or read request
     193             :      *
     194             :      */
     195             :     static void Run(System::Layer * aSystemLayer, void * apAppState);
     196             : 
     197             :     CHIP_ERROR ScheduleBufferPressureEventDelivery(uint32_t aBytesWritten);
     198             :     void GetMinEventLogPosition(uint32_t & aMinLogPosition);
     199             : 
     200             :     /**
     201             :      * If the provided path is a superset of our of our existing paths, update that existing path to match the
     202             :      * provided path.
     203             :      *
     204             :      * Return whether one of our paths is now a superset of the provided path.
     205             :      */
     206             :     bool MergeOverlappedAttributePath(const AttributePathParams & aAttributePath);
     207             : 
     208             :     /**
     209             :      * If we are running out of ObjectPool for the global dirty set, we will try to merge the existing items by clusters.
     210             :      *
     211             :      * Returns whether we have released any paths.
     212             :      */
     213             :     bool MergeDirtyPathsUnderSameCluster();
     214             : 
     215             :     /**
     216             :      * If we are running out of ObjectPool for the global dirty set and we cannot find a slot after merging the existing items by
     217             :      * clusters, we will try to merge the existing items by endpoints.
     218             :      *
     219             :      * Returns whether we have released any paths.
     220             :      */
     221             :     bool MergeDirtyPathsUnderSameEndpoint();
     222             : 
     223             :     /**
     224             :      * During the iterating of the paths, releasing the object in the inner loop will cause undefined behavior of the ObjectPool, so
     225             :      * we replace the items to be cleared by a tomb first, then clear all the tombs after the iteration.
     226             :      *
     227             :      * Returns whether we have released any paths.
     228             :      */
     229             :     bool ClearTombPaths();
     230             : 
     231             :     CHIP_ERROR InsertPathIntoDirtySet(const AttributePathParams & aAttributePath);
     232             : 
     233        2680 :     inline void BumpDirtySetGeneration() { mDirtyGeneration++; }
     234             : 
     235             :     /**
     236             :      * Boolean to indicate if ScheduleRun is pending. This flag is used to prevent calling ScheduleRun multiple times
     237             :      * within the same execution context to avoid applying too much pressure on platforms that use small, fixed size event queues.
     238             :      *
     239             :      */
     240             :     bool mRunScheduled = false;
     241             : 
     242             :     /**
     243             :      * The number of report date request in flight
     244             :      *
     245             :      */
     246             :     uint32_t mNumReportsInFlight = 0;
     247             : 
     248             :     /**
     249             :      *  Current read handler index
     250             :      *
     251             :      */
     252             :     uint32_t mCurReadHandlerIdx = 0;
     253             : 
     254             :     /**
     255             :      * The read handler we're calling BuildAndSendSingleReportData on right now.
     256             :      */
     257             :     ReadHandler * mRunningReadHandler = nullptr;
     258             : 
     259             :     /**
     260             :      *  mGlobalDirtySet is used to track the set of attribute/event paths marked dirty for reporting purposes.
     261             :      *
     262             :      */
     263             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     264             :     // For unit tests, always use inline allocation for code coverage.
     265             :     ObjectPool<AttributePathParamsWithGeneration, CHIP_IM_SERVER_MAX_NUM_DIRTY_SET, ObjectPoolMem::kInline> mGlobalDirtySet;
     266             : #else
     267             :     ObjectPool<AttributePathParamsWithGeneration, CHIP_IM_SERVER_MAX_NUM_DIRTY_SET> mGlobalDirtySet;
     268             : #endif
     269             : 
     270             :     /**
     271             :      * A generation counter for the dirty attrbute set.
     272             :      * ReadHandlers can save the generation value when generating reports.
     273             :      *
     274             :      * Then we can tell whether they might have missed reporting an attribute by
     275             :      * comparing its generation counter to the saved one.
     276             :      *
     277             :      * mDirtySetGeneration will increase by one when SetDirty is called.
     278             :      *
     279             :      * Count it from 1, so 0 can be used in ReadHandler to indicate "the read handler has never
     280             :      * completed a report".
     281             :      */
     282             :     uint64_t mDirtyGeneration = 1;
     283             : 
     284             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     285             :     uint32_t mReservedSize          = 0;
     286             :     uint32_t mMaxAttributesPerChunk = UINT32_MAX;
     287             : #endif
     288             : 
     289             :     InteractionModelEngine * mpImEngine = nullptr;
     290             : };
     291             : 
     292             : }; // namespace reporting
     293             : }; // namespace app
     294             : }; // namespace chip

Generated by: LCOV version 1.14