diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index af19e73..ed44621 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @rdkcentral/rdke_ghec_entinfra_maintainer +* @rdkcentral/entservices-maintainers diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index eb89707..c91805a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,20 +2,20 @@ When writing review comments based on custom instructions located in .github/instructions/**.instructions.md, include a direct GitHub link to the exact violated guideline in the respective instruction file. Use the following format: - Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/.instructions.md#guideline-section-name + Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/.instructions.md#guideline-section-name ## Examples -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugin.instructions.md#interface-implementation +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugin.instructions.md#interface-implementation -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginlifecycle.instructions.md#deactivated +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginlifecycle.instructions.md#deactivated -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginimplementation.instructions.md#inter-plugin-communication +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginimplementation.instructions.md#inter-plugin-communication -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginmodule.instructions.md#module-name-convention +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginmodule.instructions.md#module-name-convention -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginconfig.instructions.md#plugin-configuration +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginconfig.instructions.md#plugin-configuration -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugincmake.instructions.md#namespace-usage +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugincmake.instructions.md#namespace-usage -Refer: https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/PluginOnboardingCompliance.instructions.md#coverity-scan-inclusion-and-test-workflow-updates-for-new-plugins +Refer: https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/PluginOnboardingCompliance.instructions.md#coverity-scan-inclusion-and-test-workflow-updates-for-new-plugins diff --git a/.github/instructions/Plugin.instructions.md b/.github/instructions/Plugin.instructions.md index 10acc91..ebda2db 100644 --- a/.github/instructions/Plugin.instructions.md +++ b/.github/instructions/Plugin.instructions.md @@ -4,10 +4,10 @@ applyTo: "**/*.cpp,**/*.h" --- # Instructions summary - 1. [Interface Implementation](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugin.instructions.md#interface-implementation) - 2. [Service Registration](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugin.instructions.md#service-registration) - 3. [JSON-RPC Stub Registration](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugin.instructions.md#json-rpc-stub-registration) - 4. [Handling Out-of-Process Plugin Failures](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Plugin.instructions.md#handling-out-of-process-plugin-failures) + 1. [Interface Implementation](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugin.instructions.md#interface-implementation) + 2. [Service Registration](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugin.instructions.md#service-registration) + 3. [JSON-RPC Stub Registration](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugin.instructions.md#json-rpc-stub-registration) + 4. [Handling Out-of-Process Plugin Failures](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Plugin.instructions.md#handling-out-of-process-plugin-failures) ### Interface Implementation diff --git a/.github/instructions/Pluginimplementation.instructions.md b/.github/instructions/Pluginimplementation.instructions.md index 864fa46..37ff810 100644 --- a/.github/instructions/Pluginimplementation.instructions.md +++ b/.github/instructions/Pluginimplementation.instructions.md @@ -3,8 +3,8 @@ applyTo: "**/**Implementation.cpp,**/**Implementation.h,**/**.cpp,**/**.h" --- # Instruction Summary - 1. [Inter-Plugin Communication](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginimplementation.instructions.md#inter-plugin-communication) - 2. [On-Demand Plugin Interface Acquisition](https://github.com/rdkcentral/entservices-infra/blob/develop/.github/instructions/Pluginimplementation.instructions.md#on-demand-plugin-interface-acquisition) + 1. [Inter-Plugin Communication](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginimplementation.instructions.md#inter-plugin-communication) + 2. [On-Demand Plugin Interface Acquisition](https://github.com/rdkcentral/entservices-usersettings/blob/develop/.github/instructions/Pluginimplementation.instructions.md#on-demand-plugin-interface-acquisition) ### Inter-Plugin Communication @@ -14,7 +14,7 @@ Plugins should use COM-RPC (e.g., use QueryInterfaceByCallsign or QueryInterface ### Example -Telemetry Plugin accessing UserSettings(via COM-RPC) through the IShell Interface API **QueryInterfaceByCallsign()** exposed for each Plugin - (Refer https://github.com/rdkcentral/entservices-infra/blob/7988b8a719e594782f041309ce2d079cf6f52863/Telemetry/TelemetryImplementation.cpp#L160 ) +Telemetry Plugin accessing UserSettings(via COM-RPC) through the IShell Interface API **QueryInterfaceByCallsign()** exposed for each Plugin - (Refer https://github.com/rdkcentral/entservices-usersettings/blob/7988b8a719e594782f041309ce2d079cf6f52863/Telemetry/TelemetryImplementation.cpp#L160 ) ```cpp _userSettingsPlugin = _service->QueryInterfaceByCallsign(USERSETTINGS_CALLSIGN); diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index aeedd6c..5c79315 100755 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -13,6 +13,7 @@ on: env: BUILD_TYPE: Debug + REPO_NAME: "usersettings" THUNDER_REF: "R4.4.1" INTERFACES_REF: "develop" AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME}} @@ -45,25 +46,25 @@ jobs: uses: actions/cache@v3 with: path: | - thunder/build/Thunder - thunder/build/entservices-apis - thunder/build/ThunderTools - thunder/install - !thunder/install/etc/WPEFramework/plugins - !thunder/install/usr/bin/RdkServicesTest - !thunder/install/usr/include/gmock - !thunder/install/usr/include/gtest - !thunder/install/usr/lib/libgmockd.a - !thunder/install/usr/lib/libgmock_maind.a - !thunder/install/usr/lib/libgtestd.a - !thunder/install/usr/lib/libgtest_maind.a - !thunder/install/usr/lib/cmake/GTest - !thunder/install/usr/lib/pkgconfig/gmock.pc - !thunder/install/usr/lib/pkgconfig/gmock_main.pc - !thunder/install/usr/lib/pkgconfig/gtest.pc - !thunder/install/usr/lib/pkgconfig/gtest_main.pc - !thunder/install/usr/lib/wpeframework/plugins - key: ${{ runner.os }}-${{ env.THUNDER_REF }}-${{ env.INTERFACES_REF }}-4 + build/Thunder + build/entservices-apis + build/ThunderTools + install + !install/etc/WPEFramework/plugins + !install/usr/bin/RdkServicesTest + !install/usr/include/gmock + !install/usr/include/gtest + !install/usr/lib/libgmockd.a + !install/usr/lib/libgmock_maind.a + !install/usr/lib/libgtestd.a + !install/usr/lib/libgtest_maind.a + !install/usr/lib/cmake/GTest + !install/usr/lib/pkgconfig/gmock.pc + !install/usr/lib/pkgconfig/gmock_main.pc + !install/usr/lib/pkgconfig/gtest.pc + !install/usr/lib/pkgconfig/gtest_main.pc + !install/usr/lib/wpeframework/plugins + key: ${{ runner.os }}-${{ env.REPO_NAME }}-${{ env.THUNDER_REF }}-${{ env.INTERFACES_REF }}-4 - name: Set up Python uses: actions/setup-python@v4 @@ -123,44 +124,32 @@ jobs: with: repository: rdkcentral/entservices-testframework path: entservices-testframework - ref: develop + ref: RDKEMW-13483_usrsett token: ${{ secrets.RDKCM_RDKE }} - - name: Checkout entservices-infra + - name: Checkout entservices-usersettings if: ${{ inputs.caller_source == 'local' }} uses: actions/checkout@v3 with: - path: entservices-infra + path: entservices-usersettings - - name: Checkout entservices-infra-testframework + - name: Checkout entservices-usersettings-testframework if: ${{ inputs.caller_source == 'testframework' }} uses: actions/checkout@v3 with: - repository: rdkcentral/entservices-infra - path: entservices-infra + repository: rdkcentral/entservices-usersettings + path: entservices-usersettings ref: develop - name: Checkout googletest - if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 with: repository: google/googletest path: googletest ref: v1.15.0 - # Fetching only the required essos-resmgr.h file from the Westeros repo to avoid full repo clone and to remove header file dependency - - name: Fetch only essos-resmgr.h from Westeros repo using sparse-checkout - run: | - mkdir -p $GITHUB_WORKSPACE/westeros-minimal - cd $GITHUB_WORKSPACE/westeros-minimal - git init - git remote add origin https://code.rdkcentral.com/r/components/opensource/westeros - git config core.sparseCheckout true - git pull --depth=1 origin master - mkdir -p $GITHUB_WORKSPACE/entservices-infra/ResourceManager - cp essos/essos-resmgr.h $GITHUB_WORKSPACE/entservices-infra/ResourceManager/ - - name: Apply patches ThunderTools + if: steps.cache.outputs.cache-hit != 'true' run: | cd $GITHUB_WORKSPACE/ThunderTools patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/00010-R4.4-Add-support-for-project-dir.patch @@ -182,6 +171,7 @@ jobs: cmake --install build/ThunderTools - name: Apply patches Thunder + if: steps.cache.outputs.cache-hit != 'true' run: | cd $GITHUB_WORKSPACE/Thunder patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Use_Legact_Alt_Based_On_ThunderTools_R4.4.3.patch @@ -211,7 +201,6 @@ jobs: cmake --install build/Thunder - name: Checkout entservices-apis - if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 with: repository: rdkcentral/entservices-apis @@ -329,7 +318,6 @@ jobs: run: echo "TOOLCHAIN_FILE=$GITHUB_WORKSPACE/entservices-testframework/Tests/gcc-with-coverage.cmake" >> $GITHUB_ENV - name: Build googletest - if: steps.cache.outputs.cache-hit != 'true' run: > cmake -G Ninja -S "$GITHUB_WORKSPACE/googletest" @@ -373,9 +361,7 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/ccec/drivers -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/network -I $GITHUB_WORKSPACE/entservices-testframework/Tests - -I $GITHUB_WORKSPACE/entservices-infra/helpers - -I $GITHUB_WORKSPACE/Thunder/Source - -I $GITHUB_WORKSPACE/Thunder/Source/core + -I $GITHUB_WORKSPACE/entservices-usersettings/helpers -I $GITHUB_WORKSPACE/install/usr/include -I ./usr/include/libdrm -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -409,11 +395,11 @@ jobs: && cmake --install build/mocks - - name: Build entservices-infra + - name: Build entservices-usersettings run: > cmake -G Ninja - -S "$GITHUB_WORKSPACE/entservices-infra" - -B build/entservices-infra + -S "$GITHUB_WORKSPACE/entservices-usersettings" + -B build/entservices-usersettings -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" -DCMAKE_CXX_FLAGS=" @@ -437,8 +423,6 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/Public/Dobby -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/IpcService - -I $GITHUB_WORKSPACE/Thunder/Source - -I $GITHUB_WORKSPACE/Thunder/Source/core -I $GITHUB_WORKSPACE/install/usr/include -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -486,26 +470,12 @@ jobs: -DRDK_SERVICES_L1_TEST=ON -DUSE_THUNDER_R4=ON -DHIDE_NON_EXTERNAL_SYMBOLS=OFF - -DPLUGIN_TELEMETRY=ON - -DPLUGIN_USBDEVICE=ON - -DPLUGIN_USB_MASS_STORAGE=ON - -DPLUGIN_OCICONTAINER=ON -DPLUGIN_USERSETTINGS=ON - -DPLUGIN_RESOURCEMANAGER=ON - -DPLUGIN_APPMANAGER=ON - -DPLUGIN_STORAGE_MANAGER=ON - -DPLUGIN_RUNTIME_MANAGER=ON - -DPLUGIN_LIFECYCLE_MANAGER=ON - -DPLUGIN_MESSAGECONTROL=ON - -DPLUGIN_MIGRATION=ON - -DPLUGIN_DOWNLOADMANAGER=ON - -DPLUGIN_PREINSTALL_MANAGER=ON - -DPLUGIN_PACKAGE_MANAGER=ON -DENABLE_UNIT_TESTS=ON && - cmake --build build/entservices-infra -j8 + cmake --build build/entservices-usersettings -j8 && - cmake --install build/entservices-infra + cmake --install build/entservices-usersettings - name: Build entservices-testframework run: > @@ -530,10 +500,8 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/ccec/drivers -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/network - -I $GITHUB_WORKSPACE/entservices-infra/helpers + -I $GITHUB_WORKSPACE/entservices-usersettings/helpers -I $GITHUB_WORKSPACE/entservices-testframework/Tests - -I $GITHUB_WORKSPACE/Thunder/Source - -I $GITHUB_WORKSPACE/Thunder/Source/core -I $GITHUB_WORKSPACE/install/usr/include -I ./usr/include/libdrm -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework @@ -571,24 +539,10 @@ jobs: -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON -DCMAKE_BUILD_TYPE=Debug -DDS_FOUND=ON - -DPLUGIN_TELEMETRY=ON - -DPLUGIN_USBDEVICE=ON - -DPLUGIN_USB_MASS_STORAGE=ON -DRDK_SERVICES_L1_TEST=ON -DUSE_THUNDER_R4=ON -DHIDE_NON_EXTERNAL_SYMBOLS=OFF - -DPLUGIN_OCICONTAINER=ON -DPLUGIN_USERSETTINGS=ON - -DPLUGIN_RESOURCEMANAGER=ON - -DPLUGIN_APPMANAGER=ON - -DPLUGIN_STORAGE_MANAGER=ON - -DPLUGIN_RUNTIME_MANAGER=ON - -DPLUGIN_LIFECYCLE_MANAGER=ON - -DPLUGIN_MESSAGECONTROL=ON - -DPLUGIN_MIGRATION=ON - -DPLUGIN_DOWNLOADMANAGER=ON - -DPLUGIN_PREINSTALL_MANAGER=ON - -DPLUGIN_PACKAGE_MANAGER=ON -DENABLE_UNIT_TESTS=ON && cmake --build build/entservices-testframework -j8 @@ -692,7 +646,7 @@ jobs: rm -rf $(pwd)/rdkL1TestResults.json - name: Run unit tests with valgrind - if: ${{ !env.ACT }} + if: ${{ !env.ACT && inputs.caller_source != 'testframework' }} run: > PATH=$GITHUB_WORKSPACE/install/usr/bin:${PATH} LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install/usr/lib:$GITHUB_WORKSPACE/install/usr/lib/wpeframework/plugins:${LD_LIBRARY_PATH} @@ -709,18 +663,18 @@ jobs: rm -rf $(pwd)/rdkL1TestResults.json - name: Generate coverage - if: ${{ matrix.coverage == 'with-coverage' && !env.ACT }} + if: ${{ matrix.coverage == 'with-coverage' && !env.ACT && inputs.caller_source != 'testframework' }} run: > cp $GITHUB_WORKSPACE/entservices-testframework/Tests/L1Tests/.lcovrc_l1 ~/.lcovrc && lcov -c -o coverage.info - -d build/entservices-infra + -d build/entservices-usersettings && lcov -r coverage.info '/usr/include/*' - '*/build/entservices-infra/_deps/*' + '*/build/entservices-usersettings/_deps/*' '*/install/usr/include/*' '*/Tests/headers/*' '*/Tests/mocks/*' @@ -730,14 +684,14 @@ jobs: && genhtml -o coverage - -t "entservices-infra coverage" + -t "entservices-usersettings coverage" filtered_coverage.info - name: Upload artifacts if: ${{ !env.ACT }} uses: actions/upload-artifact@v4 with: - name: artifacts-L1-infra + name: artifacts-L1-usersettings path: | coverage/ valgrind_log diff --git a/.github/workflows/L2-tests-oop.yml b/.github/workflows/L2-tests-oop.yml index 7361f21..ae6a151 100755 --- a/.github/workflows/L2-tests-oop.yml +++ b/.github/workflows/L2-tests-oop.yml @@ -108,27 +108,34 @@ jobs: ref: develop token: ${{ secrets.RDKCM_RDKE }} - - name: Checkout entservices-deviceanddisplay + - name: Checkout entservices-persistentstore uses: actions/checkout@v3 with: - repository: rdkcentral/entservices-deviceanddisplay - path: entservices-deviceanddisplay + repository: rdkcentral/entservices-persistentstore + path: entservices-persistentstore ref: develop - - name: Checkout entservices-infra + - name: Checkout entservices-usersettings if: ${{ inputs.caller_source == 'local' }} uses: actions/checkout@v3 with: - path: entservices-infra + path: entservices-usersettings - - name: Checkout entservices-infra-testframework + - name: Checkout entservices-usersettings-testframework if: ${{ inputs.caller_source == 'testframework' }} uses: actions/checkout@v3 with: - repository: rdkcentral/entservices-infra - path: entservices-infra + repository: rdkcentral/entservices-usersettings + path: entservices-usersettings ref: develop + - name: Checkout entservices-persistentstore + uses: actions/checkout@v3 + with: + repository: rdkcentral/entservices-persistentstore + path: entservices-persistentstore + ref: feature/RDKEMW-13477 + - name: Apply ThunderTools run: | cd $GITHUB_WORKSPACE/ThunderTools @@ -157,6 +164,7 @@ jobs: patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/1004-Add-support-for-project-dir.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/RDKEMW-733-Add-ENTOS-IDS.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Jsonrpc_dynamic_error_handling.patch + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Increase_Timout_For_L2Tests_Plugin.patch cd - - name: Build Thunder run: > @@ -199,6 +207,13 @@ jobs: cp "$GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/interfaces/IPowerManagerHal.h" "$GITHUB_WORKSPACE/entservices-apis/apis/PowerManagerHal/" cp "$GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/interfaces/IMfr.h" "$GITHUB_WORKSPACE/entservices-apis/apis/Mfr/" + - name: Apply patches entservices-apis + run: | + cd $GITHUB_WORKSPACE/entservices-apis + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/RDKEMW-1007.patch + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/add-l2tests-interface.patch + cd - + - name: Build entservices-apis run: > cmake -G Ninja @@ -224,6 +239,9 @@ jobs: headers/rdk/iarmmgrs-hal headers/systemservices headers/systemservices/proc + headers/Dobby + headers/Dobby/Public/Dobby + headers/Dobby/IpcService && cd headers && @@ -280,6 +298,10 @@ jobs: rdk/ds/AudioStereoMode.hpp rdk/ds/VideoDFC.hpp dsRpc.h + Dobby/DobbyProtocol.h + Dobby/DobbyProxy.h + Dobby/Public/Dobby/IDobbyProxy.h + Dobby/IpcService/IpcFactory.h && cp -r /usr/include/gstreamer-1.0/gst /usr/include/glib-2.0/* /usr/lib/x86_64-linux-gnu/glib-2.0/include/* /usr/local/include/trower-base64/base64.h /usr/include/libdrm/drm.h /usr/include/libdrm/drm_mode.h /usr/include/xf86drm.h . @@ -328,15 +350,16 @@ jobs: && cmake --install build/mocks - - name: Build entservices-infra + - name: Build entservices-persistentstore run: > cmake - -S "$GITHUB_WORKSPACE/entservices-infra" - -B build/entservices-infra + -S "$GITHUB_WORKSPACE/entservices-persistentstore" + -B build/entservices-persistentstore -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" -DHIDE_NON_EXTERNAL_SYMBOLS=OFF + -DPLUGIN_CLOUDSTORE_URI="localhost:50051" -DCMAKE_CXX_FLAGS=" -DEXCEPTIONS_ENABLE=ON -fprofile-arcs @@ -356,7 +379,11 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/libusb -I $GITHUB_WORKSPACE/install/usr/include - -I ./usr/include/libdrm + -I $GITHUB_WORKSPACE/build/mocks + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/Public/Dobby + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/IpcService -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h @@ -377,6 +404,13 @@ jobs: -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsODM.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvTypes.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/essos-resmgr.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Dobby.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/i_omi_proxy.hpp + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/omi_proxy.hpp + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/DobbyProtocol.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/DobbyProxy.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/Public/Dobby/IDobbyProxy.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/IpcService/IpcFactory.h -Werror -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= -DUSE_IARMBUS -DHAS_RBUS @@ -385,6 +419,7 @@ jobs: -DENABLE_THERMAL_PROTECTION" -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -DPLUGIN_STORAGE_MANAGER_PATH="/tmp/persistent/storageManager" -DCOMCAST_CONFIG=OFF -DCMAKE_DISABLE_FIND_PACKAGE_DS=ON -DCMAKE_DISABLE_FIND_PACKAGE_IARMBus=ON @@ -392,6 +427,79 @@ jobs: -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON -DPLUGIN_PERSISTENTSTORE=ON + -DUSE_THUNDER_R4=ON + -DPLUGIN_L2Tests=OFF + -DRDK_SERVICE_L2_TEST=OFF + -DDS_FOUND=ON + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + && + cmake --build build/entservices-persistentstore -j6 + && + cmake --install build/entservices-persistentstore + + - name: Build entservices-usersettings + run: > + cmake + -S "$GITHUB_WORKSPACE/entservices-usersettings" + -B build/entservices-usersettings + -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" + -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" + -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DHIDE_NON_EXTERNAL_SYMBOLS=OFF + -DCMAKE_CXX_FLAGS=" + -DEXCEPTIONS_ENABLE=ON + -fprofile-arcs + -ftest-coverage + -DUSE_THUNDER_R4=ON + -DTHUNDER_VERSION=4 + -DTHUNDER_VERSION_MAJOR=4 + -DTHUNDER_VERSION_MINOR=4 + -DDEVICE_TYPE=AVOutputTV + -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" + -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/ds + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmbus + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/libusb + -I $GITHUB_WORKSPACE/install/usr/include + -I ./usr/include/libdrm + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/RBus.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Udev.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Wraps.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/libusb/libusb.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/maintenanceMGR.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/pkg.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/secure_wrappermock.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/wpa_ctrl_mock.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/readprocMockInterface.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/btmgr.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tr181api.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettings.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvError.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsExtODM.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsODM.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvTypes.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/essos-resmgr.h + -Werror -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= + -DUSE_IARMBUS + -DHAS_RBUS + -DRDK_SERVICE_L2_TEST + -DDISABLE_SECURITY_TOKEN + -DENABLE_THERMAL_PROTECTION" + -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" + -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -DCOMCAST_CONFIG=OFF + -DCMAKE_DISABLE_FIND_PACKAGE_DS=ON + -DCMAKE_DISABLE_FIND_PACKAGE_IARMBus=ON + -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON + -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON + -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON -DPLUGIN_USERSETTINGS=ON -DUSE_THUNDER_R4=ON -DPLUGIN_L2Tests=ON @@ -405,9 +513,9 @@ jobs: -DPLUGIN_ANALYTICS_SIFT_URL="127.0.0.1:12345" -DPLUGIN_ANALYTICS_EVENTS_MAP="/tmp/AnalyticsEventsMap.json" && - cmake --build build/entservices-infra -j8 + cmake --build build/entservices-usersettings -j8 && - cmake --install build/entservices-infra + cmake --install build/entservices-usersettings - name: Build entservices-testframework run: > @@ -436,7 +544,7 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc - -I $GITHUB_WORKSPACE/entservices-deviceanddisplay/helpers + -I $GITHUB_WORKSPACE/entservices-usersettings/helpers -I $GITHUB_WORKSPACE/install/usr/include -I ./usr/include/libdrm -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -471,7 +579,6 @@ jobs: -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON - -DPLUGIN_PERSISTENTSTORE=ON -DPLUGIN_USERSETTINGS=ON -DUSE_THUNDER_R4=ON -DPLUGIN_L2Tests=ON @@ -591,7 +698,7 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Run unit tests with valgrind - if: ${{ !env.ACT }} + if: ${{ !env.ACT && inputs.caller_source != 'testframework' }} run: > PATH=$GITHUB_WORKSPACE/install/usr/bin:${PATH} LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install/usr/lib:$GITHUB_WORKSPACE/install/usr/lib/wpeframework/plugins:${LD_LIBRARY_PATH} @@ -607,7 +714,7 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Generate coverage - if: ${{ matrix.coverage == 'with-coverage' && !env.ACT }} + if: ${{ matrix.coverage == 'with-coverage' && !env.ACT && inputs.caller_source != 'testframework' }} run: > cp $GITHUB_WORKSPACE/entservices-testframework/Tests/L2Tests/.lcovrc_l2 ~/.lcovrc && @@ -618,7 +725,7 @@ jobs: lcov -r coverage.info '/usr/include/*' - '*/build/entservices-infra/_deps/*' + '*/build/entservices-usersettings/_deps/*' '*/build/entservices-deviceanddisplay/_deps/*' '*/build/entservices-entservices-testframework/_deps/*' '*/install/usr/include/*' @@ -639,7 +746,7 @@ jobs: if: ${{ !env.ACT }} uses: actions/upload-artifact@v4 with: - name: artifacts-L2-oop-infra + name: artifacts-L2-oop-usersettings path: | coverage/ valgrind_log diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index 9db2202..350669f 100755 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -88,25 +88,25 @@ jobs: path: ThunderTools ref: R4.4.3 - - name: Checkout entservices-infra + - name: Checkout entservices-usersettings if: ${{ inputs.caller_source == 'local' }} uses: actions/checkout@v3 with: - path: entservices-infra + path: entservices-usersettings - - name: Checkout entservices-infra-testframework + - name: Checkout entservices-usersettings-testframework if: ${{ inputs.caller_source == 'testframework' }} uses: actions/checkout@v3 with: - repository: rdkcentral/entservices-infra - path: entservices-infra + repository: rdkcentral/entservices-usersettings + path: entservices-usersettings ref: develop - - name: Checkout entservices-deviceanddisplay + - name: Checkout entservices-persistentstore uses: actions/checkout@v3 with: - repository: rdkcentral/entservices-deviceanddisplay - path: entservices-deviceanddisplay + repository: rdkcentral/entservices-persistentstore + path: entservices-persistentstore ref: develop - name: Checkout entservices-testframework @@ -117,6 +117,13 @@ jobs: ref: develop token: ${{ secrets.RDKCM_RDKE }} + - name: Checkout entservices-persistentstore + uses: actions/checkout@v3 + with: + repository: rdkcentral/entservices-persistentstore + path: entservices-persistentstore + ref: feature/RDKEMW-13477 + - name: Checkout googletest if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 @@ -125,18 +132,6 @@ jobs: path: googletest ref: v1.15.0 - # Fetching only the required essos-resmgr.h file from the Westeros repo to avoid full repo clone and to remove header file dependency - - name: Fetch only essos-resmgr.h from Westeros repo using sparse-checkout - run: | - mkdir -p $GITHUB_WORKSPACE/westeros-minimal - cd $GITHUB_WORKSPACE/westeros-minimal - git init - git remote add origin https://code.rdkcentral.com/r/components/opensource/westeros - git config core.sparseCheckout true - git pull --depth=1 origin master - mkdir -p $GITHUB_WORKSPACE/entservices-infra/ResourceManager - cp essos/essos-resmgr.h $GITHUB_WORKSPACE/entservices-infra/ResourceManager/ - - name: Apply patches ThunderTools run: | cd $GITHUB_WORKSPACE/ThunderTools @@ -165,6 +160,7 @@ jobs: patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/1004-Add-support-for-project-dir.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/RDKEMW-733-Add-ENTOS-IDS.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Jsonrpc_dynamic_error_handling.patch + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Increase_Timout_For_L2Tests_Plugin.patch cd - - name: Build Thunder run: > @@ -196,6 +192,7 @@ jobs: run: | cd $GITHUB_WORKSPACE/entservices-apis patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/RDKEMW-1007.patch + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/add-l2tests-interface.patch cd - - name: Build entservices-apis @@ -335,15 +332,16 @@ jobs: && cmake --install build/mocks - - name: Build entservices-deviceanddisplay + - name: Build entservices-persistentstore run: > cmake - -S "$GITHUB_WORKSPACE/entservices-deviceanddisplay" - -B build/entservices-deviceanddisplay + -S "$GITHUB_WORKSPACE/entservices-persistentstore" + -B build/entservices-persistentstore -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" -DHIDE_NON_EXTERNAL_SYMBOLS=OFF + -DPLUGIN_CLOUDSTORE_URI="localhost:50051" -DCMAKE_CXX_FLAGS=" -DEXCEPTIONS_ENABLE=ON -fprofile-arcs @@ -361,14 +359,20 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc - -I $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/libusb -I $GITHUB_WORKSPACE/install/usr/include + -I $GITHUB_WORKSPACE/build/mocks + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/Public/Dobby + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/IpcService -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/RBus.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Udev.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Wraps.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/libusb/libusb.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/maintenanceMGR.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/pkg.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/secure_wrappermock.h @@ -382,44 +386,44 @@ jobs: -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsODM.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvTypes.h -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/essos-resmgr.h - -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= - -Wl,-wrap,system -Wl,-wrap,popen -Wl,-wrap,syslog -Wl,-wrap,v_secure_system -Wl,-wrap,v_secure_popen -Wl,-wrap,v_secure_pclose -Wl,-wrap,unlink + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Dobby.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/i_omi_proxy.hpp + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/omi_proxy.hpp + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/DobbyProtocol.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/DobbyProxy.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/Public/Dobby/IDobbyProxy.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/Dobby/IpcService/IpcFactory.h + -Werror -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= -DUSE_IARMBUS - -DENABLE_ERM - -DRDK_LOG_MILESTONE + -DHAS_RBUS -DRDK_SERVICE_L2_TEST -DDISABLE_SECURITY_TOKEN - -DHAS_API_POWERSTATE -DENABLE_THERMAL_PROTECTION" -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -DPLUGIN_STORAGE_MANAGER_PATH="/tmp/persistent/storageManager" -DCOMCAST_CONFIG=OFF -DCMAKE_DISABLE_FIND_PACKAGE_DS=ON -DCMAKE_DISABLE_FIND_PACKAGE_IARMBus=ON -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON - -DPLUGIN_SYSTEMSERVICES=ON - -DPLUGIN_POWERMANAGER=ON - -DPLUGIN_DISPLAYSETTINGS=OFF - -DPLUGIN_USERPREFERENCES=OFF - -DPLUGIN_DEVICEDIAGNOSTICS=OFF - -DPLUGIN_WAREHOUSE=OFF + -DPLUGIN_PERSISTENTSTORE=ON -DUSE_THUNDER_R4=ON -DPLUGIN_L2Tests=ON - -DRDK_SERVICE_L2_TEST=ON + -DRDK_SERVICE_L2_TEST=OFF -DDS_FOUND=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} && - cmake --build build/entservices-deviceanddisplay -j8 + cmake --build build/entservices-persistentstore -j6 && - cmake --install build/entservices-deviceanddisplay + cmake --install build/entservices-persistentstore - - name: Build entservices-infra + - name: Build entservices-usersettings run: > cmake - -S "$GITHUB_WORKSPACE/entservices-infra" - -B build/entservices-infra + -S "$GITHUB_WORKSPACE/entservices-usersettings" + -B build/entservices-usersettings -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" @@ -482,40 +486,22 @@ jobs: -DRDK_SERVICE_L2_TEST -DDISABLE_SECURITY_TOKEN -DENABLE_THERMAL_PROTECTION" - -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" - -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" - -DPLUGIN_STORAGE_MANAGER_PATH="/tmp/persistent/storageManager" -DCOMCAST_CONFIG=OFF -DCMAKE_DISABLE_FIND_PACKAGE_DS=ON -DCMAKE_DISABLE_FIND_PACKAGE_IARMBus=ON -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON - -DPLUGIN_MIGRATION=ON - -DPLUGIN_TELEMETRY=ON -DPLUGIN_USERSETTINGS=ON - -DPLUGIN_PERSISTENTSTORE=ON - -DPLUGIN_SHAREDSTORAGE=ON - -DPLUGIN_RESOURCEMANAGER=ON - -DPLUGIN_CLOUDSTORE=ON - -DPLUGIN_USBDEVICE=ON - -DPLUGIN_USB_MASS_STORAGE=ON - -DPLUGIN_LIFECYCLEMANAGER=OFF - -DPLUGIN_APPMANAGER=OFF - -DPLUGIN_ANALYTICS=ON - -DPLUGIN_ANALYTICS_BACKEND_LIBRARY_NAME="libWPEFrameworkAnalyticsBackendMock.so" - -DPLUGIN_ANALYTICS_EVENTS_MAP="/tmp/AnalyticsEventsMap.json" -DUSE_THUNDER_R4=ON -DPLUGIN_L2Tests=ON -DRDK_SERVICE_L2_TEST=ON - -DPLUGIN_STORAGE_MANAGER=ON - -DPLUGIN_OCICONTAINER=ON -DDS_FOUND=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} && - cmake --build build/entservices-infra -j6 + cmake --build build/entservices-usersettings -j6 && - cmake --install build/entservices-infra + cmake --install build/entservices-usersettings - name: Build entservices-testframework run: > @@ -543,7 +529,7 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc - -I $GITHUB_WORKSPACE/entservices-deviceanddisplay/helpers + -I $GITHUB_WORKSPACE/entservices-usersettings/helpers -I $GITHUB_WORKSPACE/install/usr/include -I ./usr/include/libdrm -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -578,23 +564,7 @@ jobs: -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON - -DPLUGIN_TELEMETRY=ON -DPLUGIN_USERSETTINGS=ON - -DPLUGIN_PERSISTENTSTORE=ON - -DPLUGIN_RESOURCEMANAGER=ON - -DPLUGIN_SHAREDSTORAGE=ON - -DPLUGIN_CLOUDSTORE=ON - -DPLUGIN_USBDEVICE=ON - -DPLUGIN_USB_MASS_STORAGE=ON - -DPLUGIN_ANALYTICS=ON - -DPLUGIN_ANALYTICS_BACKEND_LIBRARY_NAME="libWPEFrameworkAnalyticsBackendMock.so" - -DPLUGIN_ANALYTICS_EVENTS_MAP="/tmp/AnalyticsEventsMap.json" - -DPLUGIN_LIFECYCLEMANAGER=OFF - -DPLUGIN_APPMANAGER=OFF - -DPLUGIN_AVINPUT=OFF - -DPLUGIN_AVOUTPUT=OFF - -DAVOUTPUT_TV=OFF - -DPLUGIN_STORAGE_MANAGER=ON -DUSE_THUNDER_R4=ON -DPLUGIN_L2Tests=ON -DRDK_SERVICE_L2_TEST=ON @@ -712,7 +682,7 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Run unit tests with valgrind - if: ${{ !env.ACT }} + if: ${{ !env.ACT && inputs.caller_source != 'testframework' }} run: > PATH=$GITHUB_WORKSPACE/install/usr/bin:${PATH} LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install/usr/lib:$GITHUB_WORKSPACE/install/usr/lib/wpeframework/plugins:${LD_LIBRARY_PATH} @@ -728,18 +698,18 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Generate coverage - if: ${{ matrix.coverage == 'with-coverage' && !env.ACT }} + if: ${{ matrix.coverage == 'with-coverage' && !env.ACT && inputs.caller_source != 'testframework' }} run: > cp $GITHUB_WORKSPACE/entservices-testframework/Tests/L2Tests/.lcovrc_l2 ~/.lcovrc && lcov -c -o coverage.info - -d build/entservices-infra + -d build/entservices-usersettings && lcov -r coverage.info '/usr/include/*' - '*/build/entservices-infra/_deps/*' + '*/build/entservices-usersettings/_deps/*' '*/build/entservices-deviceanddisplay/_deps/*' '*/build/entservices-entservices-testframework/_deps/*' '*/install/usr/include/*' @@ -754,14 +724,14 @@ jobs: && genhtml -o coverage - -t "entservices-infra coverage" + -t "entservices-usersettings coverage" filtered_coverage.info - name: Upload artifacts if: ${{ !env.ACT }} uses: actions/upload-artifact@v4 with: - name: artifacts-L2-infra + name: artifacts-L2-usersettings path: | coverage/ valgrind_log diff --git a/.github/workflows/native_full_build.yml b/.github/workflows/native_full_build.yml index a64e0cc..6cdbfdc 100644 --- a/.github/workflows/native_full_build.yml +++ b/.github/workflows/native_full_build.yml @@ -8,7 +8,7 @@ on: jobs: build-entservices-on-pr: - name: Build entservices-infra component in github rdkcentral + name: Build entservices-usersettings component in GitHub rdkcentral runs-on: ubuntu-latest container: image: ghcr.io/rdkcentral/docker-rdk-ci:latest diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..5e5d1e8 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,174 @@ +# UserSettings Plugin Architecture + +## Overview + +The UserSettings plugin is a Thunder/WPEFramework-based service that provides a centralized management system for user preferences and settings in RDK-based devices. It exposes JSON-RPC APIs for applications to retrieve and modify user settings while persisting data through the PersistentStore plugin. + +## System Architecture + +### Component Structure + +``` +┌─────────────────────────────────────────────────────────┐ +│ Client Applications │ +│ (Web Apps, Native Apps, Services) │ +└────────────────────┬────────────────────────────────────┘ + │ JSON-RPC API + ▼ +┌─────────────────────────────────────────────────────────┐ +│ UserSettings Plugin │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ UserSettings (JSONRPC Handler) │ │ +│ │ - Manages JSON-RPC API endpoints │ │ +│ │ - Validates input parameters │ │ +│ │ - Forwards requests to implementation │ │ +│ └────────────────┬────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────▼────────────────────────────────┐ │ +│ │ UserSettingsImplementation │ │ +│ │ - Business logic and data management │ │ +│ │ - Default value handling │ │ +│ │ - Event notification management │ │ +│ │ - Interface: IUserSettings, IUserSettingsInspector │ +│ └────────────────┬────────────────────────────────┘ │ +└───────────────────┼────────────────────────────────────┘ + │ + ▼ COM-RPC Interface +┌─────────────────────────────────────────────────────────┐ +│ PersistentStore Plugin │ +│ - Key-value storage (IStore2 interface) │ +│ - Change notifications │ +│ - Persistent data management │ +└─────────────────────────────────────────────────────────┘ +``` + +### Key Components + +1. **UserSettings Class** (UserSettings.h/cpp) + - Inherits from `PluginHost::IPlugin` and `PluginHost::JSONRPC` + - Implements JSON-RPC endpoint handlers + - Manages plugin lifecycle (Initialize, Deinitialize) + - Handles client connection notifications + +2. **UserSettingsImplementation Class** (UserSettingsImplementation.h/cpp) + - Implements `IUserSettings`, `IUserSettingsInspector`, and `IConfiguration` interfaces + - Manages settings storage and retrieval via PersistentStore + - Maintains default values for all settings + - Broadcasts change notifications to registered clients + - Provides singleton instance for internal access + +3. **Notification System** + - Two-tier notification architecture: + - Store notifications: Listens to PersistentStore changes + - Client notifications: Broadcasts changes to registered clients + - Event-driven architecture ensures consistency across components + +## Data Flow + +### Setting Retrieval Flow +``` +Client Request → JSON-RPC Handler → UserSettingsImplementation +→ PersistentStore (IStore2) → Return Value or Default +``` + +### Setting Update Flow +``` +Client Update → JSON-RPC Handler → UserSettingsImplementation +→ Validation → PersistentStore (IStore2) → Store Notification +→ Broadcast to Registered Clients +``` + +## Plugin Framework Integration + +### Thunder Framework Integration +- Uses Thunder's COM-RPC mechanism for inter-plugin communication +- Implements standard Thunder plugin interfaces (`IPlugin`, `JSONRPC`) +- Follows Thunder configuration and lifecycle management +- Leverages Thunder's security token mechanism (when enabled) + +### Dependencies +- **PersistentStore Plugin**: Required for data persistence (queried via `org.rdk.PersistentStore` callsign) +- **Thunder Core**: Provides COM-RPC, JSONRPC, and plugin infrastructure +- **Thunder Interfaces**: Uses standardized interfaces (IUserSettings, IStore2) + +### Configuration +- Plugin name: `UserSettings` +- Namespace: `UserSettings` +- Config file: `UserSettings.config` +- Startup order: 51 (configurable) +- Auto-start: Enabled by default + +## Technical Implementation + +### Settings Management +The plugin manages 18 different user settings categorized into: + +1. **Audio Settings** + - Audio description (boolean) + - Preferred audio languages (string) + +2. **Caption Settings** + - Captions enabled (boolean) + - Preferred caption languages (string) + - Closed caption service preference (string) + +3. **Parental Control Settings** + - PIN control (boolean) + - Viewing restrictions (string) + - Viewing restrictions window (string) + - Live/playback watershed (boolean) + - Block not-rated content (boolean) + - PIN on purchase (boolean) + - Content PIN (string) + +4. **Accessibility Settings** + - Presentation language (string) + - High contrast mode (boolean) + - Voice guidance enabled (boolean) + - Voice guidance rate (numeric: 0.1-10) + - Voice guidance hints (boolean) + +5. **Privacy Settings** + - Privacy mode (string) + +### Thread Safety +- Uses mutex locks (`_adminLock`) to protect shared data structures +- Thread-safe notification registration and broadcasting +- Atomic operations for client list management + +### Error Handling +- Returns Thunder error codes (`Core::ERROR_*`) +- Validates input parameters before processing +- Gracefully handles PersistentStore unavailability +- Default value fallback mechanism + +## Inspector Interface + +The UserSettingsInspector interface (`IUserSettingsInspector`) provides: +- Bulk retrieval of multiple settings in a single call +- Efficient querying for system monitoring and diagnostics +- Reduced API overhead for applications needing multiple settings + +## Build System + +### CMake Configuration +- Plugin library: `WPEFrameworkUserSettings.so` +- Implementation library: `WPEFrameworkUserSettingsImplementation.so` +- C++11 standard compliance +- Integrates with Thunder's build system via `write_config()` + +### Helper Dependencies +- `UtilsJsonRpc.h`: JSON-RPC utility macros +- `UtilsLogging.h`: Logging infrastructure + +## Testing Infrastructure + +### L1 Unit Tests +- Component-level testing of implementation logic +- Mock-based testing framework +- Code coverage tracking via lcov + +### L2 Integration Tests +- End-to-end API testing +- Multi-component interaction validation +- Workflow and scenario-based testing diff --git a/Analytics/Analytics.conf.in b/Analytics/Analytics.conf.in deleted file mode 100644 index d268fef..0000000 --- a/Analytics/Analytics.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.Analytics" -autostart = "@PLUGIN_ANALYTICS_AUTOSTART@" -startuporder = "@PLUGIN_ANALYTICS_STARTUPORDER@" - -configuration = JSON() - -configuration.add("eventsmap", "@PLUGIN_ANALYTICS_EVENTS_MAP@") -configuration.add("loggername", "@PLUGIN_ANALYTICS_LOGGER_NAME@") -configuration.add("loggerversion", "@PLUGIN_ANALYTICS_LOGGER_VERSION@") -configuration.add("backendlib", "@PLUGIN_ANALYTICS_BACKEND_LIBRARY_NAME@") - diff --git a/Analytics/Analytics.config b/Analytics/Analytics.config deleted file mode 100644 index f69231f..0000000 --- a/Analytics/Analytics.config +++ /dev/null @@ -1,15 +0,0 @@ -set (autostart ${PLUGIN_ANALYTICS_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.Analytics") - -if(PLUGIN_ANALYTICS_STARTUPORDER) -set (startuporder ${PLUGIN_ANALYTICS_STARTUPORDER}) -endif() - -map() - kv(eventsmap, ${PLUGIN_ANALYTICS_EVENTS_MAP}) - kv(loggername, ${PLUGIN_ANALYTICS_LOGGER_NAME}) - kv(loggerversion, ${PLUGIN_ANALYTICS_LOGGER_VERSION}) - kv(backendlib, ${PLUGIN_ANALYTICS_BACKEND_LIBRARY_NAME}) -end() -ans(configuration) diff --git a/Analytics/Analytics.cpp b/Analytics/Analytics.cpp deleted file mode 100644 index dbfa368..0000000 --- a/Analytics/Analytics.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Analytics.h" -#include - -#define API_VERSION_NUMBER_MAJOR ANALYTICS_MAJOR_VERSION -#define API_VERSION_NUMBER_MINOR ANALYTICS_MINOR_VERSION -#define API_VERSION_NUMBER_PATCH ANALYTICS_PATCH_VERSION - -namespace WPEFramework { - -namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - SERVICE_REGISTRATION(Analytics, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - Analytics::Analytics(): mConnectionId(0), mAnalytics(nullptr) - { - SYSLOG(Logging::Startup, (_T("Analytics Constructor"))); - } - - Analytics::~Analytics() - { - SYSLOG(Logging::Shutdown, (string(_T("Analytics Destructor")))); - } - - /* virtual */ const string Analytics::Initialize(PluginHost::IShell* service) - { - ASSERT(service != nullptr); - ASSERT(mAnalytics == nullptr); - - SYSLOG(Logging::Startup, (_T("Analytics::Initialize: PID=%u"), getpid())); - - mService = service; - - mAnalytics = service->Root(mConnectionId, 2000, _T("AnalyticsImplementation")); - ASSERT(mAnalytics != nullptr); - - if (mAnalytics != nullptr) { - auto configConnection = mAnalytics->QueryInterface(); - if (configConnection != nullptr) { - configConnection->Configure(service); - configConnection->Release(); - } - // Invoking Plugin API register to wpeframework - Exchange::JAnalytics::Register(*this, mAnalytics); - } - else - { - SYSLOG(Logging::Startup, (_T("Analytics::Initialize: Failed to initialise Analytics plugin"))); - } - // On success return empty, to indicate there is no error text. - return ((mAnalytics != nullptr)) - ? EMPTY_STRING - : _T("Could not retrieve the Analytics interface."); - } - - /* virtual */ void Analytics::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Shutdown, (string(_T("Analytics::Deinitialize")))); - ASSERT(service == mService); - - if (mAnalytics != nullptr) { - Exchange::JAnalytics::Unregister(*this); - - RPC::IRemoteConnection *connection(service->RemoteConnection(mConnectionId)); - VARIABLE_IS_NOT_USED uint32_t result = mAnalytics->Release(); - mAnalytics = nullptr; - - // It should have been the last reference we are releasing, - // so it should end up in a DESCRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (connection != nullptr) - { - // Lets trigger a cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :~) - connection->Terminate(); - connection->Release(); - } - } - SYSLOG(Logging::Shutdown, (string(_T("Analytics de-initialised")))); - } - - void Analytics::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) { - - ASSERT(mService != nullptr); - - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - -} // namespace Plugin -} // namespace WPEFramework \ No newline at end of file diff --git a/Analytics/Analytics.h b/Analytics/Analytics.h deleted file mode 100644 index 3aac8bc..0000000 --- a/Analytics/Analytics.h +++ /dev/null @@ -1,75 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" - -#include -#include -#include - -namespace WPEFramework { - - namespace Plugin { - - - // This is a server for a JSONRPC communication channel. - // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. - // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. - // This realization of this interface implements, by default, the following methods on this plugin - // - exists - // - register - // - unregister - // Any other methood to be handled by this plugin can be added can be added by using the - // templated methods Register on the PluginHost::JSONRPC class. - // As the registration/unregistration of notifications is realized by the class PluginHost::JSONRPC, - // this class exposes a public method called, Notify(), using this methods, all subscribed clients - // will receive a JSONRPC message as a notification, in case this method is called. - class Analytics : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - // We do not allow this plugin to be copied !! - Analytics(const Analytics&) = delete; - Analytics& operator=(const Analytics&) = delete; - - public: - Analytics(); - virtual ~Analytics(); - virtual const string Initialize(PluginHost::IShell* shell) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - - BEGIN_INTERFACE_MAP(Analytics) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IAnalytics, mAnalytics) - END_INTERFACE_MAP - - static const string ANALYTICS_METHOD_SEND_EVENT; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* mService; - uint32_t mConnectionId; - Exchange::IAnalytics* mAnalytics; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/Analytics/CHANGELOG.md b/Analytics/CHANGELOG.md deleted file mode 100644 index 63c0546..0000000 --- a/Analytics/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -All notable changes to this RDK Service will be documented in this file. - - Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - - Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - Added for new features. - Changed for changes in existing functionality. - Deprecated for soon-to-be removed features. - Removed for now removed features. - Fixed for any bug fixes. - Security in case of vulnerabilities. - - Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - - For more details, refer to versioning section under Main README. - -## [1.0.5] - 2025-11-25 -- sendEvent supports optional param 'additionalContext' - -## [1.0.4] - 2025-06-12 -- Backend as an external dynamic library - -## [1.0.3] - 2025-02-07 -### Fixed -- Fix hang on call to zdump - -## [1.0.2] - 2024-12-17 -- Support optional event mapping json configuration - diff --git a/Analytics/CMakeLists.txt b/Analytics/CMakeLists.txt deleted file mode 100644 index 832299f..0000000 --- a/Analytics/CMakeLists.txt +++ /dev/null @@ -1,103 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME Analytics) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(VERSION_MAJOR 1) -set(VERSION_MINOR 0) -set(VERSION_PATCH 5) - -add_compile_definitions(ANALYTICS_MAJOR_VERSION=${VERSION_MAJOR}) -add_compile_definitions(ANALYTICS_MINOR_VERSION=${VERSION_MINOR}) -add_compile_definitions(ANALYTICS_PATCH_VERSION=${VERSION_PATCH}) - -set(MODULE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) - -set(PLUGIN_ANALYTICS_STARTUPORDER "" CACHE STRING "To configure startup order of Analytics plugin") -set(PLUGIN_ANALYTICS_AUTOSTART "false" CACHE STRING "Automatically start Analytics plugin") -set(PLUGIN_ANALYTICS_EVENTS_MAP "" CACHE STRING "Optional path to events mapping file") -set(PLUGIN_ANALYTICS_LOGGER_NAME "${PLUGIN_NAME}" CACHE STRING "Logger name") -set(PLUGIN_ANALYTICS_LOGGER_VERSION "${MODULE_VERSION}" CACHE STRING "Logger version") -set(PLUGIN_ANALYTICS_BACKEND_LIBRARY_NAME "" CACHE STRING "Analytics backend library name") - -message("Setup ${MODULE_NAME} v${MODULE_VERSION}") - -set(PLUGIN_ANALYTICS_INTERFACES_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/${NAMESPACE}/interfaces/analytics/") -set(PLUGIN_ANALYTICS_LIBLOADER_DFL_DIR "${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins/") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - Analytics.cpp - Implementation/AnalyticsImplementation.cpp - Module.cpp) - -target_include_directories(${MODULE_NAME} PRIVATE Implementation) -target_include_directories(${MODULE_NAME} PRIVATE Implementation/SystemTime) -target_include_directories(${MODULE_NAME} PRIVATE Implementation/LocalStore) -target_include_directories(${MODULE_NAME} PRIVATE Implementation/Backend) -target_include_directories(${MODULE_NAME} PRIVATE Implementation/Interfaces) -target_include_directories(${MODULE_NAME} PRIVATE ../) -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) - -file(GLOB PLUGIN_ANALYTICS_INTERFACES_HEADERS Implementation/Interfaces/I*.h) -message(STATUS "Installing Analytics interfaces: ${PLUGIN_ANALYTICS_INTERFACES_HEADERS} into ${PLUGIN_ANALYTICS_INTERFACES_INSTALL_DIR}") -install(FILES ${PLUGIN_ANALYTICS_INTERFACES_HEADERS} - DESTINATION ${PLUGIN_ANALYTICS_INTERFACES_INSTALL_DIR}) - -add_subdirectory(Implementation/SystemTime) -add_subdirectory(Implementation/LocalStore) -add_subdirectory(Implementation/Backend) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) -target_compile_definitions(${MODULE_NAME} PRIVATE LIBLOADER_DFL_DIR="${PLUGIN_ANALYTICS_LIBLOADER_DFL_DIR}") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions - ${MODULE_NAME}Backends - ${MODULE_NAME}SystemTime - ${MODULE_NAME}LocalStore) - -if (RDK_SERVICE_L2_TEST) - target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - target_compile_options(${MODULE_NAME} PRIVATE -Wno-error) - - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${MODULE_NAME} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) - - add_subdirectory(Tests/AnalyticsBackendMock) -endif (RDK_SERVICES_L2_TEST) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/Analytics/Implementation/AnalyticsImplementation.cpp b/Analytics/Implementation/AnalyticsImplementation.cpp deleted file mode 100644 index 000491a..0000000 --- a/Analytics/Implementation/AnalyticsImplementation.cpp +++ /dev/null @@ -1,509 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "AnalyticsImplementation.h" -#include "UtilsLogging.h" -#include "LocalStore.h" - -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - const uint32_t POPULATE_DEVICE_INFO_RETRY_MS = 3000; - - class AnalyticsConfig : public Core::JSON::Container { - private: - AnalyticsConfig(const AnalyticsConfig&) = delete; - AnalyticsConfig& operator=(const AnalyticsConfig&) = delete; - - public: - AnalyticsConfig() - : Core::JSON::Container() - , EventsMap() - , BackendLib() - { - Add(_T("eventsmap"), &EventsMap); - Add(_T("backendlib"), &BackendLib); - } - ~AnalyticsConfig() - { - } - - public: - Core::JSON::String EventsMap; - Core::JSON::String BackendLib; - }; - - SERVICE_REGISTRATION(AnalyticsImplementation, 1, 0); - - AnalyticsImplementation::AnalyticsImplementation(): - mQueueMutex(), - mQueueCondition(), - mActionQueue(), - mEventQueue(), - mBackends(), - mBackendLoader(), - mSysTimeValid(false), - mShell(nullptr) - { - mThread = std::thread(&AnalyticsImplementation::ActionLoop, this); - } - - AnalyticsImplementation::~AnalyticsImplementation() - { - LOGINFO("AnalyticsImplementation::~AnalyticsImplementation()"); - std::unique_lock lock(mQueueMutex); - mActionQueue.push({ACTION_TYPE_SHUTDOWN, nullptr}); - lock.unlock(); - mQueueCondition.notify_one(); - mThread.join(); - } - - /* virtual */ Core::hresult AnalyticsImplementation::SendEvent(const string& eventName, - const string& eventVersion, - const string& eventSource, - const string& eventSourceVersion, - IStringIterator* const& cetList, - const uint64_t epochTimestamp, - const uint64_t uptimeTimestamp, - const string& appId, - const string& eventPayload, - const string& additionalContext) - { - std::shared_ptr event = std::make_shared(); - event->eventName = eventName; - event->eventVersion = eventVersion; - event->eventSource = eventSource; - event->eventSourceVersion = eventSourceVersion; - - if (cetList != nullptr) - { - std::string entry; - while (cetList->Next(entry) == true) - { - event->cetList.push_back(entry); - } - } - event->epochTimestamp = epochTimestamp; - event->uptimeTimestamp = uptimeTimestamp; - event->appId = appId; - event->eventPayload = eventPayload; - event->additionalContext = additionalContext; - - bool valid = true; - if (eventName.empty()) - { - LOGERR("eventName is empty"); - valid = false; - } - if (eventSource.empty()) - { - LOGERR("eventSource is empty"); - valid = false; - } - if (eventSourceVersion.empty()) - { - LOGERR("eventSourceVersion is empty"); - valid = false; - } - if (eventPayload.empty()) - { - LOGERR("eventPayload is empty"); - valid = false; - } - - if (valid == false) - { - return Core::ERROR_GENERAL; - } - - // Fill the uptime if no time provided - if (event->epochTimestamp == 0 && event->uptimeTimestamp == 0) - { - event->uptimeTimestamp = GetCurrentUptimeInMs(); - } - - std::unique_lock lock(mQueueMutex); - mActionQueue.push({ACTION_TYPE_SEND_EVENT, event}); - lock.unlock(); - mQueueCondition.notify_one(); - return Core::ERROR_NONE; - } - - uint32_t AnalyticsImplementation::Configure(PluginHost::IShell* shell) - { - LOGINFO("Configuring Analytics"); - uint32_t result = Core::ERROR_NONE; - ASSERT(shell != nullptr); - mShell = shell; - - try { - mSysTime = std::make_shared(shell); - } catch (const std::bad_alloc& e) { - LOGERR("Failed to create SystemTime instance: %s", e.what()); - return Core::ERROR_GENERAL; - } - - std::string configLine = mShell->ConfigLine(); - Core::OptionalType error; - AnalyticsConfig config; - - if (config.FromString(configLine, error) == false) - { - SYSLOG(Logging::ParsingError, - (_T("Failed to parse config line, error: '%s', config line: '%s'."), - (error.IsSet() ? error.Value().Message().c_str() : "Unknown"), - configLine.c_str())); - } - - LOGINFO("EventsMap: %s", config.EventsMap.Value().c_str()); - ParseEventsMapFile(config.EventsMap.Value()); - - // TODO: Add support for multiple backends - uint32_t ret = mBackendLoader.Load(config.BackendLib.Value()); - if (ret != Core::ERROR_NONE) - { - LOGERR("Failed to load backend library: %s, error code: %u", - config.BackendLib.Value().c_str(), ret); - } - else - { - IAnalyticsBackendPtr backend = mBackendLoader.GetBackend(); - if (backend != nullptr) - { - mBackends[backend->Name()] = backend; - LOGINFO("Created backend: %s", backend->Name().c_str()); - // Configure backend - ILocalStorePtr localStore = std::make_shared(); - if (localStore == nullptr) - { - LOGERR("Failed to create LocalStore instance"); - result = Core::ERROR_GENERAL; - } - if (backend->Configure(mShell, mSysTime, std::move(localStore)) != Core::ERROR_NONE) - { - LOGERR("Failed to configure backend: %s", backend->Name().c_str()); - result = Core::ERROR_GENERAL; - } - else - { - LOGINFO("Backend %s configured successfully", backend->Name().c_str()); - } - } - else - { - LOGERR("Failed to get backend from loader"); - result = Core::ERROR_GENERAL; - } - } - - return result; - } - - void AnalyticsImplementation::ActionLoop() - { - std::unique_lock lock(mQueueMutex); - - while (true) { - - std::chrono::milliseconds queueTimeout(std::chrono::milliseconds::max()); - - if (!mSysTimeValid) - { - queueTimeout = std::chrono::milliseconds(POPULATE_DEVICE_INFO_RETRY_MS); - } - - if (mActionQueue.empty()) - { - if (queueTimeout == std::chrono::milliseconds::max()) - { - mQueueCondition.wait(lock, [this] - { return !mActionQueue.empty(); }); - } - else - { - mQueueCondition.wait_for(lock, queueTimeout, [this] - { return !mActionQueue.empty(); }); - } - } - - Action action = {ACTION_TYPE_UNDEF, nullptr}; - - if (mActionQueue.empty() && !mSysTimeValid) - { - action = {ACTION_POPULATE_TIME_INFO, nullptr}; - } - else if (!mActionQueue.empty()) - { - action = mActionQueue.front(); - mActionQueue.pop(); - } - - lock.unlock(); - - switch (action.type) { - case ACTION_POPULATE_TIME_INFO: - - mSysTimeValid = IsSysTimeValid(); - - if ( mSysTimeValid ) - { - // Send the events from the queue, if there are any. - while ( !mEventQueue.empty() ) - { - AnalyticsImplementation::Event event = mEventQueue.front(); - // convert uptime to epoch timestamp - if (event.epochTimestamp == 0) - { - event.epochTimestamp = ConvertUptimeToTimestampInMs(event.uptimeTimestamp); - } - - SendEventToBackend( event ); - mEventQueue.pop(); - } - } - break; - case ACTION_TYPE_SEND_EVENT: - - if (mSysTimeValid) - { - // Add epoch timestamp if needed - // It should have at least uptime already - if (action.payload->epochTimestamp == 0) - { - action.payload->epochTimestamp = ConvertUptimeToTimestampInMs(action.payload->uptimeTimestamp); - } - - SendEventToBackend(*action.payload); - } - else - { - // pass to backend if epoch available - if (action.payload->epochTimestamp != 0) - { - SendEventToBackend(*action.payload); - } - else - { - // Store the event in the queue with uptime only - mEventQueue.push(*action.payload); - LOGINFO("SysTime not ready, event awaiting in queue: %s", action.payload->eventName.c_str()); - } - } - break; - case ACTION_TYPE_SHUTDOWN: - LOGINFO("Shutting down Analytics"); - return; - default: - break; - } - - lock.lock(); - } - } - - bool AnalyticsImplementation::IsSysTimeValid() - { - bool ret = false; - // Time is valid if system time is available and time zone is set - if (mSysTime != nullptr) - { - if (mSysTime->IsSystemTimeAvailable()) - { - int32_t offset = 0; - SystemTime::TimeZoneAccuracy acc = mSysTime->GetTimeZoneOffset(offset); - if (acc == SystemTime::TimeZoneAccuracy::FINAL) - { - ret = true; - } - } - } - - return ret; - } - - void AnalyticsImplementation::SendEventToBackend(const AnalyticsImplementation::Event& event) - { - IAnalyticsBackend::Event backendEvent; - backendEvent.eventName = mEventMapper.MapEventNameIfNeeded(event.eventName, event.eventSource, - event.eventSourceVersion, event.eventVersion); - backendEvent.eventVersion = event.eventVersion; - backendEvent.eventSource = event.eventSource; - backendEvent.eventSourceVersion = event.eventSourceVersion; - backendEvent.epochTimestamp = event.epochTimestamp; - backendEvent.eventPayload = event.eventPayload; - backendEvent.appId = event.appId; - backendEvent.cetList = event.cetList; - backendEvent.additionalContext = event.additionalContext; - - //TODO: Add mapping of event source/name to the desired backend - if (mBackends.empty()) - { - LOGINFO("No backends available!"); - } - else //send to the first backend - { - LOGINFO("Sending event '%s' to backend: %s", backendEvent.eventName.c_str(), mBackends.begin()->first.c_str()); - mBackends.begin()->second->SendEvent(backendEvent); - } - } - - void AnalyticsImplementation::ParseEventsMapFile(const std::string& eventsMapFile) - { - if (eventsMapFile.empty()) - { - LOGINFO("Events map file path is empty, skipping parsing"); - return; - } - std::ifstream t(eventsMapFile); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - mEventMapper.FromString(str); - } - - uint64_t AnalyticsImplementation::GetCurrentTimestampInMs() - { - return std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count(); - } - - uint64_t AnalyticsImplementation::GetCurrentUptimeInMs() - { - struct sysinfo info = {0}; - sysinfo(&info); - return info.uptime * 1000; - } - - uint64_t AnalyticsImplementation::ConvertUptimeToTimestampInMs(uint64_t uptimeMs) - { - uint64_t uptimeDiff = 0; - uint64_t currentUptime = GetCurrentUptimeInMs(); - uint64_t currentTimestamp = GetCurrentTimestampInMs(); - if (currentUptime > uptimeMs) - { - uptimeDiff = currentUptime - uptimeMs; - } - - return currentTimestamp - uptimeDiff; - } - - void AnalyticsImplementation::EventMapper::FromString(const std::string &jsonArrayStr) - { - // expect json array: - // [ - // { - // "event_name": "event_name", - // "event_source": "event_source", - // "event_source_version": "event_source_version", - optional - // "event_version": "event_version", - optional - // "mapped_event_name": "mapped_event_name" - // } - // ] - if (jsonArrayStr.empty()) - { - LOGERR("Empty events map json array string"); - return; - } - - JsonArray array; - array.FromString(jsonArrayStr); - - if (array.Length() == 0) - { - LOGERR("Empty or corrupted events map json array"); - return; - } - - for (int i = 0; i < array.Length(); i++) - { - JsonObject entry = array[i].Object(); - if (entry.HasLabel("event_name") && entry.HasLabel("event_source") && entry.HasLabel("mapped_event_name")) - { - AnalyticsImplementation::EventMapper::Key key{ - entry["event_name"].String(), - entry["event_source"].String(), - entry.HasLabel("event_source_version") ? entry["event_source_version"].String() : "", - entry.HasLabel("event_version") ? entry["event_version"].String() : ""}; - - std::string mapped_event_name = entry["mapped_event_name"].String(); - map[key] = mapped_event_name; - LOGINFO("Index %d: Mapped event: %s -> %s", i, entry["event_name"].String().c_str(), mapped_event_name.c_str()); - } - else - { - LOGERR("Invalid entry in events map file at index %d", i); - } - } - } - - std::string AnalyticsImplementation::EventMapper::MapEventNameIfNeeded(const std::string &eventName, - const std::string &eventSource, - const std::string &eventSourceVersion, - const std::string &eventVersion) const - { - if (map.empty()) - { - return eventName; // No mapping available, return original event name - } - // Try exact match - AnalyticsImplementation::EventMapper::Key key{eventName, eventSource, eventSourceVersion, eventVersion}; - auto it = map.find(key); - if (it != map.end()) - { - return it->second; - } - - // Try without eventVersion - if (!eventVersion.empty()) - { - AnalyticsImplementation::EventMapper::Key partialKey{eventName, eventSource, eventSourceVersion, ""}; - it = map.find(partialKey); - if (it != map.end()) - { - return it->second; - } - } - - // Try without eventSourceVersion - if (!eventSourceVersion.empty()) - { - AnalyticsImplementation::EventMapper::Key partialKey{eventName, eventSource, "", eventVersion}; - it = map.find(partialKey); - if (it != map.end()) - { - return it->second; - } - } - - // Try without both eventSourceVersion and eventVersion - if (!eventSourceVersion.empty() || !eventVersion.empty()) - { - AnalyticsImplementation::EventMapper::Key partialKey{eventName, eventSource, "", ""}; - it = map.find(partialKey); - if (it != map.end()) - { - return it->second; - } - } - - return eventName; // Not found, nothing to map - } -} -} diff --git a/Analytics/Implementation/AnalyticsImplementation.h b/Analytics/Implementation/AnalyticsImplementation.h deleted file mode 100644 index 61da862..0000000 --- a/Analytics/Implementation/AnalyticsImplementation.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include "../Module.h" -#include -#include -#include "AnalyticsBackendLoader.h" -#include "SystemTime.h" - -#include -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - class AnalyticsImplementation : public Exchange::IAnalytics, public Exchange::IConfiguration { - private: - AnalyticsImplementation(const AnalyticsImplementation&) = delete; - AnalyticsImplementation& operator=(const AnalyticsImplementation&) = delete; - - public: - AnalyticsImplementation(); - ~AnalyticsImplementation(); - - BEGIN_INTERFACE_MAP(AnalyticsImplementation) - INTERFACE_ENTRY(Exchange::IAnalytics) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - private: - - enum ActionType - { - ACTION_TYPE_UNDEF, - ACTION_POPULATE_TIME_INFO, - ACTION_TYPE_SEND_EVENT, - ACTION_TYPE_SHUTDOWN, - ACTION_TYPE_SET_TIME_READY - }; - - struct Event - { - std::string eventName; - std::string eventVersion; - std::string eventSource; - std::string eventSourceVersion; - std::list cetList; - uint64_t epochTimestamp; - uint64_t uptimeTimestamp; - std::string appId; - std::string eventPayload; - std::string additionalContext; - }; - - struct Action - { - ActionType type; - std::shared_ptr payload; - std::string id; - }; - - class EventMapper - { - private: - - struct Key - { - std::string eventName; - std::string eventSource; - std::string eventSourceVersion; - std::string eventVersion; - - bool operator==(const Key &other) const - { - return eventName == other.eventName && - eventSource == other.eventSource && - eventSourceVersion == other.eventSourceVersion && - eventVersion == other.eventVersion; - } - }; - - struct KeyHasher - { - std::size_t operator()(const Key &key) const - { - std::size_t h1 = std::hash()(key.eventName); - std::size_t h2 = std::hash()(key.eventSource); - std::size_t h3 = std::hash()(key.eventSourceVersion); - std::size_t h4 = std::hash()(key.eventVersion); - - // Combine the hashes - std::size_t combined = h1; - combined ^= h2 + 0x9e3779b9 + (combined << 6) + (combined >> 2); - combined ^= h3 + 0x9e3779b9 + (combined << 6) + (combined >> 2); - combined ^= h4 + 0x9e3779b9 + (combined << 6) + (combined >> 2); - return combined; - } - }; - - public: - - void FromString(const std::string &jsonArrayStr); - std::string MapEventNameIfNeeded(const std::string &eventName, - const std::string &eventSource, - const std::string &eventSourceVersion, - const std::string &eventVersion) const; - - private: - std::unordered_map map; - }; - - // IAnalyticsImplementation interface - Core::hresult SendEvent(const string& eventName, - const string& eventVersion, - const string& eventSource, - const string& eventSourceVersion, - IStringIterator* const& cetList, - const uint64_t epochTimestamp, - const uint64_t uptimeTimestamp, - const string& appId, - const string& eventPayload, - const string& additionalContext) override; - - - // IConfiguration interface - uint32_t Configure(PluginHost::IShell* shell); - - void ActionLoop(); - bool IsSysTimeValid(); - void SendEventToBackend(const Event& event); - void ParseEventsMapFile(const std::string& eventsMapFile); - - static uint64_t GetCurrentTimestampInMs(); - static uint64_t GetCurrentUptimeInMs(); - static uint64_t ConvertUptimeToTimestampInMs(uint64_t uptimeMs); - - std::mutex mQueueMutex; - std::condition_variable mQueueCondition; - std::thread mThread; - std::queue mActionQueue; - std::queue mEventQueue; - std::map mBackends; - AnalyticsBackendLoader mBackendLoader; - bool mSysTimeValid; - PluginHost::IShell* mShell; - SystemTimePtr mSysTime; - EventMapper mEventMapper; - }; -} -} diff --git a/Analytics/Implementation/Backend/AnalyticsBackendLoader.cpp b/Analytics/Implementation/Backend/AnalyticsBackendLoader.cpp deleted file mode 100644 index cbd4dc1..0000000 --- a/Analytics/Implementation/Backend/AnalyticsBackendLoader.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include "AnalyticsBackendLoader.h" -#include "UtilsLogging.h" - -namespace WPEFramework { -namespace Plugin { - -uint32_t AnalyticsBackendLoader::Load(std::string path) -{ - if (path.empty()) { - LOGERR("Analytics backend path is empty"); - return Core::ERROR_GENERAL; - } - - std::string error; - uint32_t ret = mLibrariesLoader.Load(path, error); - if (ret != Utils::LibraryLoader::ErrorCode::NO_ERROR) - { - LOGERR("Failed to load analytics backend library (%s): %s", path.c_str(), error.c_str()); - return Core::ERROR_GENERAL; - } - - mAnalyticsBackend = mLibrariesLoader.CreateShared(error); - if (mAnalyticsBackend == nullptr) - { - LOGERR("Failed to create analytics backend object for library (%s): %s", path.c_str(), error.c_str()); - return Core::ERROR_GENERAL; - } - return Core::ERROR_NONE; - -} - -} -} \ No newline at end of file diff --git a/Analytics/Implementation/Backend/AnalyticsBackendLoader.h b/Analytics/Implementation/Backend/AnalyticsBackendLoader.h deleted file mode 100644 index d4497f1..0000000 --- a/Analytics/Implementation/Backend/AnalyticsBackendLoader.h +++ /dev/null @@ -1,48 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#pragma once - -#include -#include -#include "../../Module.h" -#include "IAnalyticsBackend.h" -#include "UtilsLibraryLoader.h" - -// Interface for Analytics Backends -namespace WPEFramework { -namespace Plugin { - - class AnalyticsBackendLoader - { - public: - AnalyticsBackendLoader() = default; - ~AnalyticsBackendLoader() = default; - - uint32_t Load(std::string path); - IAnalyticsBackendPtr GetBackend() const - { - return mAnalyticsBackend; - } - private: - Utils::LibraryLoader mLibrariesLoader; - IAnalyticsBackendPtr mAnalyticsBackend; - }; - -} -} diff --git a/Analytics/Implementation/Backend/CMakeLists.txt b/Analytics/Implementation/Backend/CMakeLists.txt deleted file mode 100644 index 0e50ad8..0000000 --- a/Analytics/Implementation/Backend/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ - -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -set(TARGET_LIB ${NAMESPACE}${PLUGIN_NAME}Backends) - -add_library(${TARGET_LIB} STATIC) - -target_sources(${TARGET_LIB} PRIVATE AnalyticsBackendLoader.cpp) -target_include_directories(${TARGET_LIB} PUBLIC "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics/Implementation/Interfaces") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/helpers") - -target_compile_definitions(${TARGET_LIB} PRIVATE LIBLOADER_DFL_DIR="${PLUGIN_ANALYTICS_LIBLOADER_DFL_DIR}") - -set_property(TARGET ${TARGET_LIB} PROPERTY POSITION_INDEPENDENT_CODE ON) -set_target_properties(${TARGET_LIB} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF) -target_link_libraries(${TARGET_LIB} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) diff --git a/Analytics/Implementation/Interfaces/IAnalyticsBackend.h b/Analytics/Implementation/Interfaces/IAnalyticsBackend.h deleted file mode 100644 index d114d90..0000000 --- a/Analytics/Implementation/Interfaces/IAnalyticsBackend.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once -#include -#include -#include - -#include "ISystemTime.h" -#include "ILocalStore.h" - - -// Interface for Analytics Backends -namespace WPEFramework { -namespace Plugin { - - struct IAnalyticsBackend { - virtual ~IAnalyticsBackend() = default; - - struct Event - { - std::string eventName; - std::string eventVersion; - std::string eventSource; - std::string eventSourceVersion; - std::list cetList; - uint64_t epochTimestamp; - std::string appId; - std::string eventPayload; - std::string additionalContext; - }; - - virtual const std::string& Name() const = 0; - - virtual uint32_t Configure(PluginHost::IShell* shell, ISystemTimePtr sysTime, ILocalStorePtr store) = 0; - virtual uint32_t SendEvent(const Event& event) = 0; - }; - - using IAnalyticsBackendPtr = std::shared_ptr; -} -} \ No newline at end of file diff --git a/Analytics/Implementation/Interfaces/ILocalStore.h b/Analytics/Implementation/Interfaces/ILocalStore.h deleted file mode 100644 index dc57f85..0000000 --- a/Analytics/Implementation/Interfaces/ILocalStore.h +++ /dev/null @@ -1,45 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#pragma once - -#include -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - struct ILocalStore - { - virtual ~ILocalStore() = default; - virtual bool Open(const std::string &path) = 0; - virtual bool CreateTable(const std::string &table) = 0; - virtual bool SetLimit(const std::string &table, uint32_t limit) = 0; - virtual std::pair GetEntriesCount(const std::string &table, uint32_t start, uint32_t maxCount) const = 0; - virtual std::vector GetEntries(const std::string &table, uint32_t start, uint32_t count) const = 0; - virtual bool RemoveEntries(const std::string &table, uint32_t start, uint32_t end) = 0; - virtual bool AddEntry(const std::string &table, const std::string &entry) = 0; - }; - - using ILocalStorePtr = std::shared_ptr; - - } -} \ No newline at end of file diff --git a/Analytics/Implementation/Interfaces/ISystemTime.h b/Analytics/Implementation/Interfaces/ISystemTime.h deleted file mode 100644 index ad49c03..0000000 --- a/Analytics/Implementation/Interfaces/ISystemTime.h +++ /dev/null @@ -1,50 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -#include - -namespace WPEFramework -{ - namespace Plugin - { - struct ISystemTime - { - public: - enum TimeZoneAccuracy - { - INITIAL, - INTERIM, - FINAL, - ACC_UNDEFINED - }; - - virtual ~ISystemTime() = default; - - virtual bool IsSystemTimeAvailable() = 0; - virtual TimeZoneAccuracy GetTimeZoneOffset(int32_t &offsetSec) = 0; - }; - - using ISystemTimePtr = std::shared_ptr; - } -} \ No newline at end of file diff --git a/Analytics/Implementation/LocalStore/CMakeLists.txt b/Analytics/Implementation/LocalStore/CMakeLists.txt deleted file mode 100644 index 23966bf..0000000 --- a/Analytics/Implementation/LocalStore/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -set(TARGET_LIB ${NAMESPACE}${PLUGIN_NAME}LocalStore) - -add_library(${TARGET_LIB} STATIC) - -target_sources(${TARGET_LIB} PRIVATE LocalStore.cpp - DatabaseConnection.cpp) - -find_package(Sqlite) -if (SQLITE_FOUND) - include_directories(${SQLITE_INCLUDE_DIRS}) - target_link_libraries(${TARGET_LIB} PRIVATE ${SQLITE_LIBRARIES}) -else (SQLITE_FOUND) - message ("Sqlite3 required.") -endif (SQLITE_FOUND) - -target_include_directories(${TARGET_LIB} PUBLIC "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics/Implementation/Interfaces") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/helpers") -set_property(TARGET ${TARGET_LIB} PROPERTY POSITION_INDEPENDENT_CODE ON) -set_target_properties(${TARGET_LIB} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF) -target_link_libraries(${TARGET_LIB} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) diff --git a/Analytics/Implementation/LocalStore/DatabaseConnection.cpp b/Analytics/Implementation/LocalStore/DatabaseConnection.cpp deleted file mode 100644 index 1dc7ad9..0000000 --- a/Analytics/Implementation/LocalStore/DatabaseConnection.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "DatabaseConnection.h" -#include "UtilsLogging.h" - -namespace WPEFramework { - namespace Plugin { - - DatabaseConnection::DatabaseConnection(): mDatabaseName(), mDataBaseHandle(NULL), mMutex() {} - - DatabaseConnection::~DatabaseConnection() { - DisConnect(); - } - - bool DatabaseConnection::Connect(const std::string & databaseName) { - bool ret = false; - - // Ensure a database name is given - if (!databaseName.empty()) { - // If a connection is already open close it first - if (mDataBaseHandle != NULL && DisConnect() != DB_OK) { - LOGERR("Database %s open failed: could not close existing " - "connection", - databaseName.c_str()); - } else { - // Assign database name - mDatabaseName = databaseName; - - // Opens a database or creates one with create and rw privileges - int32_t queryRet = DB_OPEN((const char * ) databaseName.c_str(), & mDataBaseHandle); - - // Handle result from DB query - if (DB_OK == queryRet) { - ret = true; - LOGINFO("Database %s open succeeded", databaseName.c_str()); - } else { - LOGERR("Database %s open failed: %s db err code %d", - databaseName.c_str(), - DB_ERRMSG(mDataBaseHandle), - queryRet); - } - } - } else { - LOGERR("Database open failed: invalid db name %s", databaseName.c_str()); - } - - return ret; - } - - bool DatabaseConnection::DisConnect() { - bool ret = false; - - // Closes a database reference by the database handle - if (mDataBaseHandle != NULL) { - // Closes a database based on the associated handle - int32_t queryRet = DB_CLOSE(mDataBaseHandle); - - // Handle result from DB query - if (DB_OK == queryRet) { - ret = true; - LOGINFO("Database %s close succeeded", mDatabaseName.c_str()); - mDatabaseName.clear(); - mDataBaseHandle = NULL; - } else { - LOGERR("Database %s close failed: %s db err code %d", - mDatabaseName.c_str(), - DB_ERRMSG(mDataBaseHandle), - queryRet); - } - } - - return ret; - } - - bool DatabaseConnection::Exec(const std::string & query) { - bool ret = false; - char * errmsg = NULL; - - std::lock_guard < std::mutex > lock(mMutex); - - // Verify the database handle was created - if (mDataBaseHandle != NULL) { - DatabaseQuery queryCbData(query, mDatabaseName); - - // Execute a generic query to the database based on the associated handle - int32_t queryRet = DB_QUERY(mDataBaseHandle, - query.c_str(), - DbCallbackOnly, - (void * ) & queryCbData, & - errmsg); - - // Handle result from DB query - if (DB_OK == queryRet) { - // Note that row data could be large and therefore cannot log query - ret = true; - } else { - LOGERR("Database %s query failed errmsg: %s db err code %d", - mDatabaseName.c_str(), - errmsg, - queryRet); - - // If error, database malloc's the message so it needs to be free'd - DB_FREE(errmsg); - } - } else { - LOGERR("Database connection not established for %s. " - "Query failed.", - mDatabaseName.c_str()); - } - - return ret; - } - - bool DatabaseConnection::ExecAndGetModified(const std::string & query, - uint32_t & modifiedRows) { - - bool ret = false; - char * errmsg = NULL; - - std::lock_guard < std::mutex > lock(mMutex); - - // Verify the database handle was created - if (mDataBaseHandle != NULL) { - DatabaseQuery queryCbData(query, mDatabaseName); - - // Execute a generic query to the database based on the associated handle - int32_t queryRet = DB_QUERY(mDataBaseHandle, - query.c_str(), - DbCallbackOnly, - (void * ) & queryCbData, & - errmsg); - - // Handle result from DB query - if (DB_OK == queryRet) { - // Executes a query to get how many rows in the table were affected - modifiedRows = DB_CHANGES(mDataBaseHandle); - ret = true; - } else { - LOGERR("Database %s query failed errmsg: %s db err code %d", - mDatabaseName.c_str(), - errmsg, - queryRet); - - // If error, database malloc's the message so it needs to be free'd - DB_FREE(errmsg); - } - } else { - LOGERR("Database connection not established for %s. " - "Query failed.", - mDatabaseName.c_str()); - } - - return ret; - } - - bool DatabaseConnection::ExecAndGetResults(const std::string & query, - DatabaseTable & table) { - bool ret = false; - char * errmsg = NULL; - - std::lock_guard < std::mutex > lock(mMutex); - - if (mDataBaseHandle != NULL) { - DatabaseTable result; - - // Execute a generic query to the database based on the associated handle - // which also returns a result to client i.e SELECT * FROM blah - int32_t queryRet = DB_QUERY(mDataBaseHandle, - query.c_str(), - DbCallbackGetResults, - (void * ) & result, & - errmsg); - - // Handle result from DB query - if (DB_OK == queryRet) { - ret = true; - table = result; - } else { - LOGERR("Database %s query failed with error: %s db err code %d", - mDatabaseName.c_str(), - errmsg, - queryRet); - DB_FREE(errmsg); - } - } else { - LOGERR("Database connection not established for %s. Query failed.", - mDatabaseName.c_str()); - } - - return ret; - } - - int32_t DatabaseConnection::DbCallbackOnly(void * arg, - int argc, - char ** argv, - char ** colName) { - int32_t ret = DB_ERROR; - DatabaseQuery * query = static_cast < DatabaseQuery * > (arg); - - if (query) { - ret = DB_OK; - } else { - LOGERR("Database query executed with no data"); - } - - return ret; - } - - int32_t DatabaseConnection::DbCallbackGetResults(void * arg, - int argc, - char ** argv, - char ** colName) { - int32_t ret = DB_ERROR; - DatabaseTable * table = static_cast < DatabaseTable * > (arg); - - if (table != NULL) { - DatabaseTable::DatabaseRow row; - - for (int index = 0; index < argc; index++) { - std::string name = colName[index]; - std::string value; - if (argv[index]) { - value = argv[index]; - } - - row.AddColEntry( - DatabaseTable::DatabaseRow::DatabaseColumnEntry(name, value)); - } - - table -> AddRow(row); - - ret = DB_OK; - - } else { - LOGERR("Database invalid query, cannot get results"); - } - - return ret; - } - - } // namespace Plugin -} // namespace WPEFramework \ No newline at end of file diff --git a/Analytics/Implementation/LocalStore/DatabaseConnection.h b/Analytics/Implementation/LocalStore/DatabaseConnection.h deleted file mode 100644 index 5b42fa1..0000000 --- a/Analytics/Implementation/LocalStore/DatabaseConnection.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#pragma once - -#include "../../Module.h" -#include "DatabaseInterface.h" - -#include -#include -#include -#include -#include - -namespace WPEFramework { - namespace Plugin { - - class DatabaseTable { - public: class DatabaseRow { - public: class DatabaseColumnEntry { - private: std::string mName; - std::string mValue; - - public: DatabaseColumnEntry(std::string & name, std::string & value): mName(name), - mValue(value) {} - - const std::string & GetName(void) const { - return mName; - } - - const std::string & GetValue(void) const { - return mValue; - } - }; - - DatabaseRow() { - mRow.clear(); - } - DatabaseColumnEntry & operator[](uint32_t idx) { - return mRow[idx]; - } - void AddColEntry(const DatabaseColumnEntry & entry) { - mRow.push_back(entry); - } - - uint32_t NumCols(void) const { - return mRow.size(); - } - - private: std::vector < DatabaseColumnEntry > mRow; - }; - - DatabaseTable() { - mTable.clear(); - } - uint32_t NumRows(void) const { - return mTable.size(); - } - DatabaseRow & operator[](uint32_t idx) { - return mTable[idx]; - } - void AddRow(const DatabaseRow & row) { - mTable.push_back(row); - } - - private: std::vector < DatabaseRow > mTable; - }; - - struct DatabaseQuery { - std::string mQuery; - std::string mDatabaseName; - - DatabaseQuery(std::string query, std::string dbName): mQuery(query), mDatabaseName(dbName) {} - }; - - class DatabaseConnection { - public: DatabaseConnection(); - ~DatabaseConnection(); - - bool Connect(const std::string & databaseName); - bool DisConnect(); - bool Exec(const std::string & query); - bool ExecAndGetModified(const std::string & query, uint32_t & modifiedRows); - bool ExecAndGetResults(const std::string & query, DatabaseTable & table); - const std::string & GetDatabaseName(void) const { - return mDatabaseName; - } - bool IsConnected(void) { - return (mDataBaseHandle != NULL); - } - - private: static int32_t DbCallbackOnly(void * arg, int argc, char ** argv, char ** colName); - static int32_t DbCallbackGetResults(void * arg, int argc, char ** argv, char ** colName); - - std::string mDatabaseName; - DB_HANDLE * mDataBaseHandle; - std::mutex mMutex; - }; - - typedef std::shared_ptr < DatabaseConnection > DatabaseConnectionPtr; - - } -} \ No newline at end of file diff --git a/Analytics/Implementation/LocalStore/DatabaseInterface.h b/Analytics/Implementation/LocalStore/DatabaseInterface.h deleted file mode 100644 index 64e3a3f..0000000 --- a/Analytics/Implementation/LocalStore/DatabaseInterface.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#pragma once - -#include "sqlite3.h" - -//============================================================================= -// Custom Definitions -#define SQL_MASTER_TABLE_NAME_COL_ID (1) - -//============================================================================= -// Database Definitions -#define DB_OK SQLITE_OK -#define DB_ERROR SQLITE_ERROR - -#define DB_ROW_READY SQLITE_ROW - -#define DB_COL_TYPE_INTEGER SQLITE_INTEGER -#define DB_COL_TYPE_FLOAT SQLITE_FLOAT -#define DB_COL_TYPE_TEXT SQLITE3_TEXT -#define DB_COL_TYPE_BLOB SQLITE_BLOB -#define DB_COL_TYPE_NULL SQLITE_NULL - -//============================================================================= -// Database Types -#define DB_HANDLE sqlite3 -#define DB_STATEMENT sqlite3_stmt - -//============================================================================= -// Database APIs -//Get last error generated by the database -#define DB_ERRMSG(handle) sqlite3_errmsg(handle) - -//Open a new/existing database -#define DB_OPEN(name, handle) sqlite3_open(name, handle) - -//Close a currently open database -#define DB_CLOSE(handle) sqlite3_close(handle) - -//Free memory created internally by the database -#define DB_FREE(ptr) sqlite3_free(ptr) - -//Query database handling 1 row at a time -#define DB_STEP_ROW(smt) sqlite3_step(smt) - -//Number of columns in the database -#define DB_COLUMN_COUNT(smt) sqlite3_column_count(smt) - -//Column name -#define DB_COLUMN_NAME(smt, colIdx) sqlite3_column_name(smt, colIdx) - -//Column Datatype -#define DB_COLUMN_TYPE(smt, colIdx) sqlite3_column_type(smt, colIdx) - -//Perform a database query based on a query string -#define DB_QUERY(handle, query, cb, cbdata, errmsg) \ - sqlite3_exec(handle, query, cb, cbdata, errmsg) - -//Check how many rows were affected on the last query -#define DB_CHANGES(handle) sqlite3_changes(handle) diff --git a/Analytics/Implementation/LocalStore/LocalStore.cpp b/Analytics/Implementation/LocalStore/LocalStore.cpp deleted file mode 100644 index 0c4586f..0000000 --- a/Analytics/Implementation/LocalStore/LocalStore.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#include "LocalStore.h" -#include "UtilsLogging.h" -#include "DatabaseConnection.h" - -#include - -namespace WPEFramework -{ - namespace Plugin - { - const std::string DB_EXT = "db"; - - LocalStore::LocalStore(): - mDatabaseConnection(nullptr), - mPath() - { - } - - LocalStore::~LocalStore() - { - } - - bool LocalStore::Open(const std::string &path) - { - bool status = false; - const std::string dbPath = path + "." + DB_EXT; - - if (mPath == dbPath && mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - status = true; - LOGINFO("Database %s already opened", dbPath.c_str()); - return status; - } - - // Creates a database connection object - DatabaseConnectionPtr conn = std::make_shared(); - - // Connects to the database, which creates the database file if needed - if (conn->Connect(dbPath)) - { - status = true; - mDatabaseConnection = conn; - mPath = dbPath; - } - else - { - LOGERR("AddDatabase failed to create a new database %s ", dbPath.c_str()); - } - - return status; - } - - bool LocalStore::CreateTable(const std::string &table) - { - bool status = false; - const std::string query = "CREATE TABLE IF NOT EXISTS " + table - + " (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT)"; - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - if (mDatabaseConnection->Exec(query)) - { - status = true; - } - else - { - LOGERR("Failed to create table %s", table.c_str()); - } - } - else - { - LOGERR("Failed to create table %s, no connection", table.c_str()); - } - - return status; - } - - bool LocalStore::SetLimit(const std::string &table, uint32_t limit) - { - bool status = false; - const std::string query = "PRAGMA max_page_count = " + std::to_string(limit); - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - if (mDatabaseConnection->Exec(query)) - { - status = true; - } - else - { - LOGERR("Failed to set limit %u", limit); - } - } - else - { - LOGERR("Failed to set limit %u, no connection", limit); - } - - return status; - } - - std::pair LocalStore::GetEntriesCount(const std::string &table, uint32_t start, uint32_t maxCount) const - { - std::pair count = std::make_pair(0, 0); - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - std::string query = buildGetEventsQuery(table, start, maxCount); - if (!query.empty()) - { - DatabaseTable table; - if (mDatabaseConnection->ExecAndGetResults(query, table) - && table.NumRows() > 0) - { - // get start from first row's id value - count.first = std::stoi(table[0][0].GetValue()); - // get count from number of rows - count.second = table.NumRows(); - } - } - else - { - LOGERR("Failed to build query with {%u, %u}", start, maxCount); - } - } - else - { - LOGERR("Failed to get entries count, no connection"); - } - - return count; - } - - std::vector LocalStore::GetEntries(const std::string &table, uint32_t start, uint32_t count) const - { - std::vector entries{}; - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - std::string query = buildGetEventsQuery(table, start, count); - if (!query.empty()) - { - DatabaseTable table; - if (mDatabaseConnection->ExecAndGetResults(query, table)) - { - for (uint32_t rowIdx = 0; rowIdx < table.NumRows(); rowIdx++) - { - if (table[rowIdx].NumCols() < 2) - { - LOGERR("Failed to get entries, invalid row"); - continue; - } - - std::string entry = table[rowIdx][1].GetValue(); - entries.push_back(entry); - } - } - else - { - LOGERR("Failed to get entries, query %s", query.c_str()); - } - } - else - { - LOGERR("Failed to build query with {%u, %u}", start, count); - } - } - else - { - LOGERR("Failed to get entries, no connection"); - } - - return entries; - } - - bool LocalStore::RemoveEntries(const std::string &table, uint32_t start, uint32_t end) - { - bool status = false; - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - std::string query = "DELETE FROM " + table + " WHERE id BETWEEN " + std::to_string(start) + " AND " + std::to_string(end); - uint32_t modifiedRows = 0; - if (mDatabaseConnection->ExecAndGetModified(query, modifiedRows)) - { - status = true; - } - else - { - LOGERR("Failed to remove entries, query %s", query.c_str()); - } - } - else - { - LOGERR("Failed to remove entries, no connection"); - } - - return status; - } - - bool LocalStore::AddEntry(const std::string &table, const std::string &entry) - { - bool status = false; - - if (mDatabaseConnection != nullptr && mDatabaseConnection->IsConnected()) - { - std::string query = "INSERT INTO " + table + " (data) VALUES ('" + entry + "')"; - if (mDatabaseConnection->Exec(query)) - { - status = true; - } - else - { - LOGERR("Failed to add entry, query %s", query.c_str()); - } - } - else - { - LOGERR("Failed to add entry, no connection"); - } - - return status; - } - - std::string LocalStore::buildGetEventsQuery(const std::string &table, uint32_t start, uint32_t count) const - { - std::string query{}; - - if (0 == start) - { - query.append("SELECT * FROM " + table); - query.append(" WHERE"); - query.append(" id>((SELECT MAX(id) FROM " + table + ")-" + - std::to_string(count) + ")"); - } - else if (start && count) - { - query.append("SELECT * FROM " + table); - query.append(" WHERE"); - query.append(" id>=" + std::to_string(start) + " LIMIT " + - std::to_string(count)); - } - else - { - LOGERR("Failed to build query with {%u, %u}", start, count); - } - - return query; - } - - } -} \ No newline at end of file diff --git a/Analytics/Implementation/LocalStore/LocalStore.h b/Analytics/Implementation/LocalStore/LocalStore.h deleted file mode 100644 index 4a222dc..0000000 --- a/Analytics/Implementation/LocalStore/LocalStore.h +++ /dev/null @@ -1,57 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include - -#include "../../Module.h" -#include "ILocalStore.h" -#include "DatabaseConnection.h" - -namespace WPEFramework -{ - namespace Plugin - { - class LocalStore: public ILocalStore - { - public: - LocalStore(); - ~LocalStore(); - - bool Open(const std::string &path) override; - bool CreateTable(const std::string &table) override; - bool SetLimit(const std::string &table, uint32_t limit) override; - std::pair GetEntriesCount(const std::string &table, uint32_t start, uint32_t maxCount) const override; - std::vector GetEntries(const std::string &table, uint32_t start, uint32_t count) const override; - bool RemoveEntries(const std::string &table, uint32_t start, uint32_t end) override; - bool AddEntry(const std::string &table, const std::string &entry) override; - private: - - std::string buildGetEventsQuery(const std::string &table, uint32_t start, uint32_t count) const; - - DatabaseConnectionPtr mDatabaseConnection; - std::string mPath; - }; - } -} diff --git a/Analytics/Implementation/SystemTime/CMakeLists.txt b/Analytics/Implementation/SystemTime/CMakeLists.txt deleted file mode 100644 index 96811cb..0000000 --- a/Analytics/Implementation/SystemTime/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -set(TARGET_LIB ${NAMESPACE}${PLUGIN_NAME}SystemTime) - -add_library(${TARGET_LIB} STATIC) - -target_sources(${TARGET_LIB} PRIVATE SystemTime.cpp) - -target_include_directories(${TARGET_LIB} PUBLIC "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics/Implementation/Interfaces") -target_include_directories(${TARGET_LIB} PRIVATE "${CMAKE_SOURCE_DIR}/helpers") -set_property(TARGET ${TARGET_LIB} PROPERTY POSITION_INDEPENDENT_CODE ON) -set_target_properties(${TARGET_LIB} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF) -target_link_libraries(${TARGET_LIB} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) diff --git a/Analytics/Implementation/SystemTime/SystemTime.cpp b/Analytics/Implementation/SystemTime/SystemTime.cpp deleted file mode 100644 index a8ee03d..0000000 --- a/Analytics/Implementation/SystemTime/SystemTime.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#include "SystemTime.h" -#include "UtilsLogging.h" -#include "secure_wrapper.h" - -#define JSONRPC_THUNDER_TIMEOUT 2000 -#define THUNDER_ACCESS_DEFAULT_VALUE "127.0.0.1:9998" -#define SYSTEM_CALLSIGN "org.rdk.System.1" - -namespace WPEFramework -{ - namespace Plugin - { - const std::string TIME_QUALITY_STALE{"Stale"}; - const std::string TIME_QUALITY_GOOD{"Good"}; - const std::string TIME_QUALITY_SECURE{"Secure"}; - - SystemTime::SystemTime(PluginHost::IShell *shell) : mQueueLock(), - mQueueCondition(), - mQueue(), - mLock(), - mSystemLink(nullptr), - mTimeQuality(TIME_QUALITY_STALE), - mTimeZone(), - mTimeZoneAccuracyString(), - mTransitionMap(), - mIsSystemTimeAvailable(false), - mShell(shell) - { - mEventThread = std::thread(&SystemTime::EventLoop, this); - - Event event = {EVENT_INITIALISE, std::string()}; - std::unique_lock lock(mQueueLock); - mQueue.push(event); - lock.unlock(); - mQueueCondition.notify_one(); - } - - SystemTime::~SystemTime() - { - LOGINFO("SystemTime::~SystemTime"); - Event event = {EVENT_SHUTDOWN, std::string()}; - { - std::lock_guard lock(mQueueLock); - mQueue.push(event); - } - mQueueCondition.notify_one(); - mEventThread.join(); - if (mSystemLink != nullptr) - { - mSystemLink->Unsubscribe(JSONRPC_THUNDER_TIMEOUT, _T("onTimeStatusChanged")); - mSystemLink->Unsubscribe(JSONRPC_THUNDER_TIMEOUT, _T("onTimeZoneDSTChanged")); - } - } - - bool SystemTime::IsSystemTimeAvailable() - { - // Time status is updated during init and on event - std::lock_guard guard(mLock); - return mIsSystemTimeAvailable; - } - - ISystemTime::TimeZoneAccuracy SystemTime::GetTimeZoneOffset(int32_t &offsetSec) - { - std::lock_guard guard(mLock); - - if (mIsSystemTimeAvailable) - { - std::pair tzParsed = ParseTimeZone(); - offsetSec = tzParsed.second; - return tzParsed.first; - } - return ACC_UNDEFINED; - } - - void SystemTime::onTimeStatusChanged(const JsonObject& parameters) - { - std::string parametersString; - parameters.ToString(parametersString); - LOGINFO("onTimeStatusChanged: %s", parametersString.c_str()); - Event event = {EVENT_TIME_STATUS_CHANGED, parametersString}; - std::lock_guard lock(mQueueLock); - mQueue.push(event); - mQueueCondition.notify_one(); - } - - void SystemTime::onTimeZoneDSTChanged(const JsonObject& parameters) - { - std::string parametersString; - parameters.ToString(parametersString); - LOGINFO("onTimeZoneDSTChanged: %s", parametersString.c_str()); - Event event = {EVENT_TIME_ZONE_CHANGED, parametersString}; - std::lock_guard lock(mQueueLock); - mQueue.push(event); - mQueueCondition.notify_one(); - } - - void SystemTime::CreateSystemLink() - { - if (mSystemLink == nullptr) - { - std::string thunderAccessValue = THUNDER_ACCESS_DEFAULT_VALUE; - char *thunderAccessValueEnv = getenv("THUNDER_ACCESS_VALUE"); - if (NULL != thunderAccessValueEnv) - { - thunderAccessValue = thunderAccessValueEnv; - } - - // Generate jsonrpc token - std::string token; - // TODO: use interfaces and remove token - auto security = mShell->QueryInterfaceByCallsign("SecurityAgent"); - if (security != nullptr) - { - std::string payload = "http://localhost"; - if (security->CreateToken( - static_cast(payload.length()), - reinterpret_cast(payload.c_str()), - token) == Core::ERROR_NONE) - { - LOGINFO("Got security token\n"); - } - else - { - LOGINFO("Failed to get security token\n"); - } - security->Release(); - } - else - { - LOGINFO("No security agent\n"); - } - - std::string query = "token=" + token; - Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), (_T(thunderAccessValue))); - mSystemLink = std::make_shared>(SYSTEM_CALLSIGN, "", false, query); - } - } - - void SystemTime::SubscribeForEvents() - { - if (mSystemLink != nullptr) - { - uint32_t ret = mSystemLink->Subscribe(JSONRPC_THUNDER_TIMEOUT, _T("onTimeStatusChanged"), &SystemTime::onTimeStatusChanged, this); - if (ret != Core::ERROR_NONE) - { - LOGERR("Failed to subscribe to onTimeStatusChanged"); - } - - ret = mSystemLink->Subscribe(JSONRPC_THUNDER_TIMEOUT, _T("onTimeZoneDSTChanged"), &SystemTime::onTimeZoneDSTChanged, this); - if (ret != Core::ERROR_NONE) - { - LOGERR("Failed to subscribe to onTimeZoneDSTChanged"); - } - } - } - - void SystemTime::UpdateTimeStatus() - { - JsonObject params; - JsonObject response; - - uint32_t result = mSystemLink->Invoke(JSONRPC_THUNDER_TIMEOUT, "getTimeStatus", params, response); - if (result == Core::ERROR_NONE && response.HasLabel("TimeQuality")) - { - std::lock_guard guard(mLock); - mTimeQuality = response["TimeQuality"].String(); - if (mTimeQuality == TIME_QUALITY_GOOD || mTimeQuality == TIME_QUALITY_SECURE) - { - mIsSystemTimeAvailable = true; - } - else - { - mIsSystemTimeAvailable = false; - } - } - else - { - LOGERR("getTimeStatus not available, assuming time is OK"); - std::lock_guard guard(mLock); - mIsSystemTimeAvailable = true; - } - } - - void SystemTime::UpdateTimeZone() - { - JsonObject params; - JsonObject response; - // Get timeZone from System.1.getTimeZoneDST - uint32_t result = mSystemLink->Invoke(JSONRPC_THUNDER_TIMEOUT, "getTimeZoneDST", params, response); - if (result == Core::ERROR_NONE && response.HasLabel("timeZone") && response.HasLabel("accuracy")) - { - std::string tz = response["timeZone"].String(); - std::string accuracy = response["accuracy"].String(); - - std::lock_guard guard(mLock); - mTimeZoneAccuracyString = accuracy; - if (accuracy == "FINAL") - { - if (mTimeZone != tz) - { - mTransitionMap.clear(); - mTimeZone = tz; - } - } - else - { - mTimeZone.clear(); - mTransitionMap.clear(); - } - } - } - - std::pair SystemTime::ParseTimeZone() - { - std::pair result = {ACC_UNDEFINED, 0}; - if (mTimeZone.empty()) - { - return result; - } - - static const std::map accuracyMap = { - {"INITIAL", INITIAL}, - {"INTERIM", INTERIM}, - {"FINAL", FINAL}}; - - auto accuracyItr = accuracyMap.find(mTimeZoneAccuracyString); - if (accuracyItr == accuracyMap.end()) - { - result.first = ACC_UNDEFINED; - } else { - result.first = accuracyItr->second; - } - - if (mTimeZone == "Universal") - { - result.second = 0; - return result; - } - - PopulateTimeZoneTransitionMap(); - - if (mTransitionMap.empty()) - { - result.first = ACC_UNDEFINED; - return result; - } - - time_t currentTime = time(NULL); - - auto currentTimeEndItr = mTransitionMap.lower_bound(currentTime); - - if (currentTimeEndItr != mTransitionMap.end()) - { - result.second = currentTimeEndItr->second; - } - else if (mTransitionMap.empty() == false) - { - currentTimeEndItr--; // take the last transition when all transitions are from past - result.second = currentTimeEndItr->second; - } - else - { - LOGERR( "There is no time transition information for this timezone: %s", mTimeZone.c_str()); - result.second = 0; - result.first = ACC_UNDEFINED; - } - - return result; - } - - void SystemTime::PopulateTimeZoneTransitionMap() - { - if (mTransitionMap.empty() && !mTimeZone.empty()) - { - std::string cmd = "zdump -v " + mTimeZone; - FILE *fp = popen(cmd.c_str(), "r"); - if (fp != NULL) - { - LOGINFO("popen of '%s' succeeded", cmd.c_str()); - - // Read entire output of zdump - char buf[4096] = {0}; - std::string output; - while (fgets(buf, sizeof(buf), fp) != NULL) - { - output += buf; - } - - pclose(fp); - - // Convert output to read line by line - std::istringstream iss(output); - std::string line; - while (std::getline(iss, line)) - { - // " Tue Jan 19 03:14:07 2038 UT = Tue Jan 19 04:14:07 2038 CET isdst=0 gmtoff=3600" - struct tm utcTime = {0}; - - line.erase(0, line.find(" ") + 2); // Remove " " -> 2 spaces - - auto utOff = line.find(" UT = "); - std::string date = line.substr(0, utOff); // Capture UTC date "Tue Jan 19 03:14:07 2038" - - // Remove everything to " UT = ", "Tue Jan 19 04:14:07 2038 CET isdst=0 gmtoff=3600" is left - line.erase(0, utOff + sizeof(" UT = ") - 1); - - // Remove until next 5 spaces, "CET isdst=0 gmtoff=3600" will be left - auto spaceCount = 5; - while (spaceCount > 0) - { - auto spOff = line.find(" "); - // In case of one-digit day of month there are two spaces before that - if (spaceCount == 4) - { - // thus + 2 to remove it (it applies also to two-digits but it's ok because it's removed anyway) - line.erase(0, spOff + 2); - } - else - { - line.erase(0, spOff + 1); - } - spaceCount--; - } - - char timeZone[5] = {0}; - int32_t isDst = 0; - int32_t gmtOff = 0; - sscanf(line.c_str(), "%s isdst=%d gmtoff=%d", timeZone, &isDst, &gmtOff); - strptime(date.c_str(), "%A %B %d %H:%M:%S %Y", &utcTime); - - // Years below 70 are not supported by epoch - if (utcTime.tm_year > 70) - { - utcTime.tm_zone = "UTC"; - utcTime.tm_gmtoff = 0; - - // years after 2038 are rounding off to -1 - if (utcTime.tm_year < 138) - { - time_t utcTimeGm = timegm(&utcTime); - mTransitionMap[utcTimeGm] = gmtOff; - } - else - { - break; // stop parsing as we wont add anything after 2038 to map - } - } - else - { - // validate the line - if (utcTime.tm_year > 0) - { - mTransitionMap[utcTime.tm_year] = gmtOff; - } - } - } - } - else - { - LOGERR("popen of zdump -v %s failed", mTimeZone.c_str()); - } - } - } - - - void SystemTime::EventLoop() - { - while (true) - { - Event event; - { - std::unique_lock lock(mQueueLock); - mQueueCondition.wait(lock, [this] - { return !mQueue.empty(); }); - event = mQueue.front(); - mQueue.pop(); - } - - switch (event.type) - { - case EVENT_INITIALISE: - { - if (mSystemLink == nullptr) - { - CreateSystemLink(); - if (mSystemLink != nullptr) - { - SubscribeForEvents(); - UpdateTimeStatus(); - UpdateTimeZone(); - } - else - { - LOGERR("Failed to create JSONRPC link with %s", SYSTEM_CALLSIGN); - } - } - } - break; - case EVENT_TIME_STATUS_CHANGED: - { - JsonObject response(event.payload); - if (response.HasLabel("TimeQuality")) - { - std::lock_guard guard(mLock); - mTimeQuality = response["TimeQuality"].String(); - if (mTimeQuality == TIME_QUALITY_GOOD || mTimeQuality == TIME_QUALITY_SECURE) - { - mIsSystemTimeAvailable = true; - } - else - { - mIsSystemTimeAvailable = false; - } - } - } - break; - case EVENT_TIME_ZONE_CHANGED: - { - JsonObject response(event.payload); - if (response.HasLabel("newTimeZone") && response.HasLabel("newAccuracy")) - { - std::string tz = response["newTimeZone"].String(); - std::string accuracy = response["newAccuracy"].String(); - - std::lock_guard guard(mLock); - mTimeZoneAccuracyString = accuracy; - if (accuracy == "FINAL") - { - if (mTimeZone != tz) - { - mTransitionMap.clear(); - mTimeZone = tz; - } - } - else - { - mTimeZone.clear(); - mTransitionMap.clear(); - } - } - } - break; - case EVENT_SHUTDOWN: - { - LOGINFO("Shutting down SystemTime event loop"); - return; - } - default: - { - LOGERR("Unhandled event received, event: %d", event.type); - break; - } - } - } - } - } -} diff --git a/Analytics/Implementation/SystemTime/SystemTime.h b/Analytics/Implementation/SystemTime/SystemTime.h deleted file mode 100644 index dc6f106..0000000 --- a/Analytics/Implementation/SystemTime/SystemTime.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "../../Module.h" -#include "ISystemTime.h" - -namespace WPEFramework -{ - namespace Plugin - { - class SystemTime: public ISystemTime - { - public: - - SystemTime(PluginHost::IShell *shell); - ~SystemTime(); - - bool IsSystemTimeAvailable() override; - TimeZoneAccuracy GetTimeZoneOffset(int32_t &offsetSec) override; - - private: - enum EventType - { - EVENT_UNDEF, - EVENT_INITIALISE, - EVENT_TIME_STATUS_CHANGED, - EVENT_TIME_ZONE_CHANGED, - EVENT_SHUTDOWN - }; - - struct Event - { - EventType type; - std::string payload; - }; - - void onTimeStatusChanged(const JsonObject& parameters); - void onTimeZoneDSTChanged(const JsonObject& parameters); - - void CreateSystemLink(); - void SubscribeForEvents(); - void UpdateTimeStatus(); - void UpdateTimeZone(); - std::pair ParseTimeZone(); - void PopulateTimeZoneTransitionMap(); - void EventLoop(); - - - std::mutex mQueueLock; - std::condition_variable mQueueCondition; - std::queue mQueue; - - std::thread mEventThread; - std::mutex mLock; - std::shared_ptr> mSystemLink; - std::string mTimeQuality; - std::string mTimeZone; - std::string mTimeZoneAccuracyString; - std::map mTransitionMap; - bool mIsSystemTimeAvailable; - PluginHost::IShell *mShell; - }; - - typedef std::shared_ptr SystemTimePtr; - } -} diff --git a/Analytics/Module.cpp b/Analytics/Module.cpp deleted file mode 100644 index 69ecca0..0000000 --- a/Analytics/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Analytics/Module.h b/Analytics/Module.h deleted file mode 100644 index d414ea8..0000000 --- a/Analytics/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_Analytics -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/Analytics/Tests/AnalyticsBackendMock/AnalyticsBackendMock.cpp b/Analytics/Tests/AnalyticsBackendMock/AnalyticsBackendMock.cpp deleted file mode 100644 index 7d65785..0000000 --- a/Analytics/Tests/AnalyticsBackendMock/AnalyticsBackendMock.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "IAnalyticsBackend.h" -#include "UtilsLogging.h" - -#include -#include -#include -#include -#include -#include - -#ifndef SERVER_URL -#define SERVER_URL "http://localhost:12345" -#endif // SERVER_URL - -namespace WPEFramework { -namespace Plugin { - - #define TABLE_NAME "events" - #define TABLE_LIMIT 1000 - - static size_t CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp) - { - ((std::string *)userp)->append((char *)contents, size * nmemb); - return size * nmemb; - } - - class AnalyticsBackendMock : public IAnalyticsBackend { - public: - AnalyticsBackendMock(): mStore(nullptr), mSysTime(nullptr) { - LOGINFO("AnalyticsBackendMock created"); - } - ~AnalyticsBackendMock() override = default; - - const std::string& Name() const override { - static std::string name = "AnalyticsBackendMock"; - return name; - } - - uint32_t Configure(PluginHost::IShell* shell, ISystemTimePtr sysTime, ILocalStorePtr store) override { - if (store) - { - mStore = store; - if (!mStore->Open("/tmp/AnalyticsStore")) { - LOGERR("Failed to open local store"); - return Core::ERROR_OPENING_FAILED; - } - if (!mStore->CreateTable(TABLE_NAME)) { - LOGERR("Failed to create events table in local store"); - return Core::ERROR_GENERAL; - } - if (!mStore->SetLimit(TABLE_NAME, TABLE_LIMIT)) { - LOGERR("Failed to set limit for events table in local store"); - return Core::ERROR_GENERAL; - } - } else { - return Core::ERROR_BAD_REQUEST; - } - - mSysTime = sysTime; - return Core::ERROR_NONE; - } - - uint32_t SendEvent(const Event& event) override { - // Mock implementation for testing purposes - // prepare json object from event - JsonObject eventJson; - eventJson["eventName"] = event.eventName; - eventJson["eventVersion"] = event.eventVersion; - eventJson["eventSource"] = event.eventSource; - eventJson["eventSourceVersion"] = event.eventSourceVersion; - JsonArray cetList; - for (const auto& cet : event.cetList) { - cetList.Add(cet); - } - eventJson["cetList"] = cetList; - eventJson["epochTimestamp"] = event.epochTimestamp; - eventJson["appId"] = event.appId; - eventJson["eventPayload"] = event.eventPayload; - - // If system time is available, get the timezone offset - if (mSysTime && mSysTime->IsSystemTimeAvailable()) { - int32_t offsetSec = 0; - auto accuracy = mSysTime->GetTimeZoneOffset(offsetSec); - if (accuracy == ISystemTime::FINAL) { - // Here you could add logic to handle the final timezone offset - eventJson["timeZoneOffset"] = offsetSec*1000; - } - } - - // Add the event to the local store - std::string entry; - eventJson.ToString(entry); - if (mStore && !mStore->AddEntry(TABLE_NAME, entry)) { - LOGERR("Failed to add event to local store"); - return Core::ERROR_GENERAL; - } - - std::string json; - - // get all events from store, should be only one in this mock implementation - if (mStore) { - uint32_t startIndex = 0; - uint32_t eventCount = 0; - - std::tie(startIndex, eventCount) = mStore->GetEntriesCount(TABLE_NAME, 0, TABLE_LIMIT); - - std::vector eventsString; - eventsString = mStore->GetEntries(TABLE_NAME, startIndex, eventCount); - if (eventsString.empty()) { - LOGERR("No events found in local store"); - return Core::ERROR_GENERAL; - } - - // Clear the store after sending - if (mStore->RemoveEntries(TABLE_NAME, 0, startIndex+eventCount)) { - LOGINFO("Removed %d events from local store", eventCount); - // Verify that the store is empty after removal - std::tie(startIndex, eventCount) = mStore->GetEntriesCount(TABLE_NAME, 0, TABLE_LIMIT); - if (eventCount != 0) - { - LOGERR("There are still %d events left in local store after removal, start %d", eventCount); - return Core::ERROR_GENERAL; - } - - } else { - LOGERR("Failed to remove events from local store"); - return Core::ERROR_GENERAL; - } - - JsonArray eventArray = JsonArray(); - for (const auto& entry : eventsString) { - JsonObject eventEntry; - if (eventEntry.FromString(entry)) { - eventArray.Add(eventEntry); - } else { - LOGERR("Failed to parse event entry: %s", entry.c_str()); - return Core::ERROR_GENERAL; - } - } - - eventArray.ToString(json); - } - - if (json.empty()) { - LOGERR("No events to send"); - return Core::ERROR_GENERAL; - } - - // Send with curl - CURL *curl; - CURLcode res; - long retHttpCode = 0; - std::string url = SERVER_URL; - std::string response; - - curl = curl_easy_init(); - if (!curl) - { - LOGERR("Failed to initialize curl"); - return Core::ERROR_GENERAL; - } - - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.data()); - - // Create a linked list of custom headers - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Content-Type: application/json"); - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); - - // Perform the request, res will get the return code - res = curl_easy_perform(curl); - - // Check for errors - if (res != CURLE_OK) - { - LOGERR("curl_easy_perform() failed: %s", curl_easy_strerror(res)); - } - else - { - LOGINFO("Response: %s", response.c_str()); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &retHttpCode); - } - - // Clean up the header list - curl_slist_free_all(headers); - - // Clean up curl session - curl_easy_cleanup(curl); - - if (retHttpCode != 200 && retHttpCode != 400) { - LOGERR("Failed to post analytics event - respcode: %ld, response: %s", retHttpCode, response.c_str()); - return Core::ERROR_GENERAL; - } - - return Core::ERROR_NONE; - } - - private: - ILocalStorePtr mStore; - ISystemTimePtr mSysTime; - }; -} // namespace Plugin -} // namespace WPEFramework - -extern "C" { - - WPEFramework::Plugin::IAnalyticsBackend* Create() - { - return new WPEFramework::Plugin::AnalyticsBackendMock(); - } - -} \ No newline at end of file diff --git a/Analytics/Tests/AnalyticsBackendMock/CMakeLists.txt b/Analytics/Tests/AnalyticsBackendMock/CMakeLists.txt deleted file mode 100644 index 819beb3..0000000 --- a/Analytics/Tests/AnalyticsBackendMock/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -set(LIB_NAME AnalyticsBackendMock) -set(MODULE_NAME ${NAMESPACE}${LIB_NAME}) - - -message("Setup ${MODULE_NAME} v${MODULE_VERSION}") - -set(LIB_ANALYTICS_MOCK_SERVER_URL "127.0.0.1:12345" CACHE STRING "Sift max randomisation window time of posting queued events") - - -add_library(${MODULE_NAME} SHARED - AnalyticsBackendMock.cpp) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -find_package(CURL) -if (CURL_FOUND) - include_directories(${CURL_INCLUDE_DIRS}) - target_link_libraries(${MODULE_NAME} PRIVATE ${CURL_LIBRARIES}) -else (CURL_FOUND) - message ("Curl/libcurl required.") -endif (CURL_FOUND) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Lib_${LIB_NAME}) - -target_compile_definitions(${MODULE_NAME} PRIVATE - SERVER_URL="${LIB_ANALYTICS_MOCK_SERVER_URL}") - -target_include_directories(${MODULE_NAME} PUBLIC "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") -target_include_directories(${MODULE_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/helpers") -target_include_directories(${MODULE_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/Analytics/Implementation/Interfaces") -target_include_directories(${MODULE_NAME} PRIVATE "${WPEFRAMEWORK_INCLUDE_DIRS}") - -set_property(TARGET ${MODULE_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) -set_target_properties(${MODULE_NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF) -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) \ No newline at end of file diff --git a/AppGateway/AppGateway.conf.in b/AppGateway/AppGateway.conf.in deleted file mode 100755 index 1b3b415..0000000 --- a/AppGateway/AppGateway.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.AppGateway" -autostart = "@PLUGIN_APPGATEWAY_AUTOSTART@" -startuporder = "@PLUGIN_APPGATEWAY_STARTUPORDER@" diff --git a/AppGateway/AppGateway.config b/AppGateway/AppGateway.config deleted file mode 100755 index d248f4d..0000000 --- a/AppGateway/AppGateway.config +++ /dev/null @@ -1,7 +0,0 @@ -set (autostart ${PLUGIN_APPGATEWAY_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.AppGateway") - -if(PLUGIN_APPGATEWAY_STARTUPORDER) -set (startuporder ${PLUGIN_APPGATEWAY_STARTUPORDER}) -endif() diff --git a/AppGateway/AppGateway.cpp b/AppGateway/AppGateway.cpp deleted file mode 100644 index c3b427a..0000000 --- a/AppGateway/AppGateway.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AppGateway.h" -#include -#include -#include -#include "UtilsLogging.h" - - -#define API_VERSION_NUMBER_MAJOR APPGATEWAY_MAJOR_VERSION -#define API_VERSION_NUMBER_MINOR APPGATEWAY_MINOR_VERSION -#define API_VERSION_NUMBER_PATCH APPGATEWAY_PATCH_VERSION - - -namespace WPEFramework { - -namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - SERVICE_REGISTRATION(AppGateway, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - AppGateway::AppGateway() - : PluginHost::JSONRPC(), mService(nullptr), mAppGateway(nullptr), mResponder(nullptr), mConnectionId(0) - { - - LOGINFO("AppGateway Constructor"); - } - - AppGateway::~AppGateway() - { - } - - /* virtual */ const string AppGateway::Initialize(PluginHost::IShell* service) - { - ASSERT(service != nullptr); - ASSERT(mAppGateway == nullptr); - ASSERT(mResponder == nullptr); - - LOGINFO("AppGateway::Initialize: PID=%u", getpid()); - - mService = service; - mService->AddRef(); - mAppGateway = service->Root(mConnectionId, 2000, _T("AppGatewayImplementation")); - - if (mAppGateway != nullptr) { - auto configConnection = mAppGateway->QueryInterface(); - if (configConnection != nullptr) { - configConnection->Configure(service); - configConnection->Release(); - } - - //Invoking Plugin API register to wpeframework - Exchange::JAppGatewayResolver::Register(*this, mAppGateway); - } - else - { - LOGERR("Failed to initialise AppGatewayResolver plugin!"); - } - - mResponder = service->Root(mConnectionId, 2000, _T("AppGatewayResponderImplementation")); - if (mResponder != nullptr) { - auto configConnectionResponder = mResponder->QueryInterface(); - if (configConnectionResponder != nullptr) { - configConnectionResponder->Configure(service); - configConnectionResponder->Release(); - } - } - else - { - LOGERR("Failed to initialise AppGatewayResponder plugin!"); - } - - - // On success return empty, to indicate there is no error text. - return ((mAppGateway != nullptr) && (mResponder != nullptr)) - ? EMPTY_STRING - : _T("Could not retrieve the AppGateway interface."); - } - - /* virtual */ void AppGateway::Deinitialize(PluginHost::IShell* service) - { - ASSERT(service == mService); - - RPC::IRemoteConnection *connection = nullptr; - VARIABLE_IS_NOT_USED uint32_t result = Core::ERROR_NONE; - - if ((mAppGateway != nullptr) || (mResponder != nullptr)) { - connection = service->RemoteConnection(mConnectionId); - } - - if (mResponder != nullptr) { - result = mResponder->Release(); - mResponder = nullptr; - - // It should have been the last reference we are releasing, - // so it should end up in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - } - - if (mAppGateway != nullptr) { - Exchange::JAppGatewayResolver::Unregister(*this); - result = mAppGateway->Release(); - mAppGateway = nullptr; - - // It should have been the last reference we are releasing, - // so it should end up in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - } - - // If this was running in a (container) process... - if (connection != nullptr) - { - // Lets trigger a cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :~) - connection->Terminate(); - connection->Release(); - } - - mConnectionId = 0; - mService->Release(); - mService = nullptr; - } - - void AppGateway::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) { - - ASSERT(mService != nullptr); - - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/AppGateway/AppGateway.h b/AppGateway/AppGateway.h deleted file mode 100644 index f928c56..0000000 --- a/AppGateway/AppGateway.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "Module.h" -#include - -namespace WPEFramework { - - namespace Plugin { - // This is a server for a JSONRPC communication channel. - // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. - // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. - // This realization of this interface implements, by default, the following methods on this plugin - // - exists - // - register - // - unregister - // Any other method to be handled by this plugin can be added can be added by using the - // templated methods Register on the PluginHost::JSONRPC class. - // As the registration/unregistration of notifications is realized by the class PluginHost::JSONRPC, - // this class exposes a public method called, Notify(), using this methods, all subscribed clients - // will receive a JSONRPC message as a notification, in case this method is called. - class AppGateway : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - // We do not allow this plugin to be copied !! - AppGateway(const AppGateway&) = delete; - AppGateway& operator=(const AppGateway&) = delete; - - public: - AppGateway(); - virtual ~AppGateway(); - - // IPlugin interface implementation - virtual const string Initialize(PluginHost::IShell *service) override; - virtual void Deinitialize(PluginHost::IShell *service) override; - virtual string Information() const override { return {}; } - - BEGIN_INTERFACE_MAP(AppGateway) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IAppGatewayResolver, mAppGateway) - INTERFACE_AGGREGATE(Exchange::IAppGatewayResponder, mResponder) - END_INTERFACE_MAP - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* mService; - Exchange::IAppGatewayResolver* mAppGateway; - Exchange::IAppGatewayResponder* mResponder; - uint32_t mConnectionId; - }; - } // namespace Plugin -} // namespace WPEFramework - diff --git a/AppGateway/AppGatewayImplementation.cpp b/AppGateway/AppGatewayImplementation.cpp deleted file mode 100644 index 92178ee..0000000 --- a/AppGateway/AppGatewayImplementation.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#include -#include -#include -#include "AppGatewayImplementation.h" -#include "UtilsLogging.h" -#include "ContextUtils.h" -#include "ObjectUtils.h" -#include -#include -#include "UtilsCallsign.h" -#include "UtilsFirebolt.h" -#include "StringUtils.h" - -#define DEFAULT_CONFIG_PATH "/etc/app-gateway/resolution.base.json" -#define RESOLUTIONS_PATH_CFG "/etc/app-gateway/resolutions.json" - -// Build and vendor config paths are defined via CMake -// These should be set in the platform-specific .bbappend file -#ifndef BUILD_CONFIG_PATH -#define BUILD_CONFIG_PATH "" -#endif - -#ifndef VENDOR_CONFIG_PATH -#define VENDOR_CONFIG_PATH "" -#endif - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(AppGatewayImplementation, 1, 0, 0); - - class RegionalResolutionConfig : public Core::JSON::Container - { - private: - RegionalResolutionConfig(const RegionalResolutionConfig &) = delete; - RegionalResolutionConfig &operator=(const RegionalResolutionConfig &) = delete; - - public: - class Region : public Core::JSON::Container - { - public: - Region() - : Core::JSON::Container() - { - Add(_T("countryCodes"), &countryCodes); - Add(_T("paths"), &paths); - } - - Region(const Region& other) - : Core::JSON::Container(), - countryCodes(other.countryCodes), - paths(other.paths) - { - Add(_T("countryCodes"), &countryCodes); - Add(_T("paths"), &paths); - } - Region& operator=(const Region& other) - { - if (this != &other) { - countryCodes = other.countryCodes; - paths = other.paths; - } - return *this; - } - ~Region() {} - - Core::JSON::ArrayType countryCodes; - Core::JSON::ArrayType paths; - - bool HasCountryCode(const std::string& country) const { - auto index = countryCodes.Elements(); - while (index.Next()) { - std::string code = index.Current().Value(); - // Case-insensitive equality using StringUtils::toLower - if (StringUtils::toLower(code) == StringUtils::toLower(country)) { - return true; - } - } - return false; - } - - std::vector GetPaths() const { - std::vector result; - auto index = paths.Elements(); - while (index.Next()) { - result.push_back(index.Current().Value().c_str()); - } - return result; - } - }; - - RegionalResolutionConfig() - : Core::JSON::Container() - { - Add(_T("defaultCountryCode"), &defaultCountryCode); - Add(_T("regions"), ®ions); - } - ~RegionalResolutionConfig() {} - - std::vector GetPathsForCountry(const std::string& country) const { - std::vector result; - - // Search through regions for matching country code - auto index = regions.Elements(); - while (index.Next()) { - const Region& region = index.Current(); - if (region.HasCountryCode(country)) { - result = region.GetPaths(); - LOGINFO("Found %zu paths for country '%s'", result.size(), country.c_str()); - return result; - } - } - - // If no match found and we have a default country, try that - if (!country.empty() && defaultCountryCode.IsSet()) { - std::string defaultCode = defaultCountryCode.Value(); - if (!defaultCode.empty() && StringUtils::toLower(country) != StringUtils::toLower(defaultCode)) { - LOGWARN("Country '%s' not found, trying default country '%s'", - country.c_str(), defaultCode.c_str()); - return GetPathsForCountry(defaultCode); - } - } - - return result; - } - - public: - Core::JSON::String defaultCountryCode; - Core::JSON::ArrayType regions; - }; - - AppGatewayImplementation::AppGatewayImplementation() - : mService(nullptr), - mResolverPtr(nullptr), - mAppNotifications(nullptr), - mAppGatewayResponder(nullptr), - mInternalGatewayResponder(nullptr), - mAuthenticator(nullptr) - { - LOGINFO("AppGatewayImplementation constructor"); - } - - AppGatewayImplementation::~AppGatewayImplementation() - { - LOGINFO("AppGatewayImplementation destructor"); - if (nullptr != mService) - { - mService->Release(); - mService = nullptr; - } - - if (nullptr != mAppNotifications) - { - mAppNotifications->Release(); - mAppNotifications = nullptr; - } - - if (nullptr != mInternalGatewayResponder) - { - mInternalGatewayResponder->Release(); - mInternalGatewayResponder = nullptr; - } - - if (nullptr != mAppGatewayResponder) - { - mAppGatewayResponder->Release(); - mAppGatewayResponder = nullptr; - } - - if (nullptr != mAuthenticator) - { - mAuthenticator->Release(); - mAuthenticator = nullptr; - } - - - // Shared pointer will automatically clean up - mResolverPtr.reset(); - } - - uint32_t AppGatewayImplementation::Configure(PluginHost::IShell *shell) - { - LOGINFO("Configuring AppGateway"); - uint32_t result = Core::ERROR_NONE; - ASSERT(shell != nullptr); - mService = shell; - mService->AddRef(); - - result = InitializeResolver(); - if (Core::ERROR_NONE != result) { - return result; - } - return result; - } - - uint32_t AppGatewayImplementation::InitializeResolver() { - // Initialize resolver after setting mService - try { - mResolverPtr = std::make_shared(mService); - } catch (const std::bad_alloc& e) { - LOGERR("Failed to create Resolver instance: %s", e.what()); - return Core::ERROR_GENERAL; - } - - // Read country from build config - std::string country = ReadCountryFromConfigFile(); - if (country.empty()) { - LOGWARN("No country found in build config, will use default from resolutions config"); - } else { - LOGINFO("Device country code: %s", country.c_str()); - } - - // Load the regional resolutions configuration - RegionalResolutionConfig regionalConfig; - Core::OptionalType error; - std::ifstream resolutionConfigFile(RESOLUTIONS_PATH_CFG); - - if (!resolutionConfigFile.is_open()) - { - LOGWARN("Failed to open resolutions config file: %s, falling back to default config", RESOLUTIONS_PATH_CFG); - - // Fallback: Load only the base resolution file - std::vector fallbackPaths = {DEFAULT_CONFIG_PATH}; - LOGINFO("Using fallback: loading default config path: %s", DEFAULT_CONFIG_PATH); - - Core::hresult configResult = InternalResolutionConfigure(std::move(fallbackPaths)); - if (configResult != Core::ERROR_NONE) { - LOGERR("Failed to configure resolutions from fallback path"); - return configResult; - } - return Core::ERROR_NONE; - } - - // Parse the regional config file - std::string configContent((std::istreambuf_iterator(resolutionConfigFile)), std::istreambuf_iterator()); - resolutionConfigFile.close(); - - if (regionalConfig.FromString(configContent, error) == false) - { - LOGERR("Failed to parse regional resolutions config file, error: '%s'", - (error.IsSet() ? error.Value().Message().c_str() : "Unknown")); - LOGWARN("Falling back to default config path: %s", DEFAULT_CONFIG_PATH); - std::vector fallbackPaths = { DEFAULT_CONFIG_PATH }; - Core::hresult configResult = InternalResolutionConfigure(std::move(fallbackPaths)); - if (configResult != Core::ERROR_NONE) { - LOGERR("Failed to configure resolutions from fallback path after parse error"); - return configResult; - } - return Core::ERROR_NONE; - } - - // If country is empty, use the default from config - if (country.empty() && regionalConfig.defaultCountryCode.IsSet()) { - country = regionalConfig.defaultCountryCode.Value(); - LOGINFO("Using default country code from config: %s", country.c_str()); - } - - // Get paths for the country - std::vector configPaths = regionalConfig.GetPathsForCountry(country); - - if (configPaths.empty()) { - LOGERR("No configuration paths found for country '%s' and no fallback available", country.c_str()); - - // Last resort fallback - configPaths = {DEFAULT_CONFIG_PATH}; - LOGWARN("Using last resort fallback: %s", DEFAULT_CONFIG_PATH); - } - - LOGINFO("Loading %zu configuration paths for country '%s'", configPaths.size(), country.c_str()); - Core::hresult configResult = InternalResolutionConfigure(std::move(configPaths)); - if (configResult != Core::ERROR_NONE) { - LOGERR("Failed to configure resolutions from country-specific paths"); - return configResult; - } - - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayImplementation::Configure(Exchange::IAppGatewayResolver::IStringIterator *const &paths) - { - LOGINFO("Call AppGatewayImplementation::Configure"); - - if (paths == nullptr) - { - LOGERR("Configure called with null paths iterator"); - return Core::ERROR_BAD_REQUEST; - } - - if (mResolverPtr == nullptr) - { - LOGERR("Resolver not initialized"); - return Core::ERROR_GENERAL; - } - - // Clear existing resolutions before loading new configuration - // mResolverPtr->ClearResolutions(); - - std::vector configPaths; - - // Collect all paths first - std::string currentPath; - while (paths->Next(currentPath) == true) - { - configPaths.push_back(currentPath); - LOGINFO("Found config path: %s", currentPath.c_str()); - } - - if (configPaths.empty()) - { - LOGERR("No valid configuration paths provided"); - return Core::ERROR_BAD_REQUEST; - } - - LOGINFO("Processing %zu configuration paths in override order", configPaths.size()); - return InternalResolutionConfigure(std::move(configPaths)); - - } - - Core::hresult AppGatewayImplementation::InternalResolutionConfigure(std::vector&& configPaths){ - // Process all paths in order - later paths override earlier ones - bool anyConfigLoaded = false; - for (size_t i = 0; i < configPaths.size(); i++) - { - const std::string &configPath = configPaths[i]; - LOGINFO("Processing config path %zu/%zu: %s", i + 1, configPaths.size(), configPath.c_str()); - - if (mResolverPtr->LoadConfig(configPath)) - { - LOGINFO("Successfully loaded configuration from: %s", configPath.c_str()); - anyConfigLoaded = true; - } - else - { - LOGERR("Failed to load configuration from: %s", configPath.c_str()); - // Continue processing other paths instead of failing completely - } - } - - if (!anyConfigLoaded) - { - LOGERR("Failed to load configuration from any provided path"); - return Core::ERROR_GENERAL; - } - - LOGINFO("Configuration complete. Final resolutions loaded with override priority (later paths take precedence)"); - return Core::ERROR_NONE; - - } - - Core::hresult AppGatewayImplementation::Resolve(const Context& context, const string& origin, const string& method, const string& params, string& resolution) - { - LOGTRACE("method=%s params=%s", method.c_str(), params.c_str()); - return InternalResolve(context, method, params, origin, resolution); - } - - Core::hresult AppGatewayImplementation::InternalResolve(const Context& context, const string& method, const string& params, const string& origin, string& resolution) - { - Core::hresult result = FetchResolvedData(context, method, params, origin, resolution); - if (!resolution.empty()) { - LOGTRACE("Final resolution: %s", resolution.c_str()); - Core::IWorkerPool::Instance().Submit(RespondJob::Create(this, context, resolution, origin)); - } - return result; - } - - Core::hresult AppGatewayImplementation::FetchResolvedData(const Context &context, const string &method, const string ¶ms, const string &origin, string& resolution) { - JsonObject params_obj; - Core::hresult result = Core::ERROR_NONE; - if (mResolverPtr == nullptr) - { - LOGERR("Resolver not initialized"); - ErrorUtils::CustomInitialize("Resolver not initialized", resolution); - return Core::ERROR_GENERAL; - } - - // Check if resolver has any resolutions loaded - if (!mResolverPtr->IsConfigured()) - { - LOGERR("Resolver not configured - no resolutions loaded. Call Configure() first."); - ErrorUtils::CustomInitialize("Resolver not configured", resolution); - return Core::ERROR_GENERAL; - } - // Resolve the alias from the method - std::string alias = mResolverPtr->ResolveAlias(method); - - if (alias.empty()) - { - LOGERR("No alias found for method: %s", method.c_str()); - ErrorUtils::NotSupported(resolution); - return Core::ERROR_GENERAL; - } - - std::string permissionGroup; - if (mResolverPtr->HasPermissionGroup(method, permissionGroup)) { - LOGTRACE("Method '%s' requires permission group '%s'", method.c_str(), permissionGroup.c_str()); - if (SetupAppGatewayAuthenticator()) { - bool allowed = false; - if (Core::ERROR_NONE != mAuthenticator->CheckPermissionGroup(context.appId, permissionGroup, allowed)) { - LOGERR("Failed to check permission group '%s' for appId '%s'", permissionGroup.c_str(), context.appId.c_str()); - ErrorUtils::NotPermitted(resolution); - return Core::ERROR_GENERAL; - } - if (!allowed) { - LOGERR("AppId '%s' not allowed in permission group '%s'", context.appId.c_str(), permissionGroup.c_str()); - ErrorUtils::NotPermitted(resolution); - return Core::ERROR_GENERAL; - } - } - } - LOGTRACE("Resolved method '%s' to alias '%s'", method.c_str(), alias.c_str()); - // Check if the given method is an event - if (mResolverPtr->HasEvent(method)) { - result = PreProcessEvent(context, alias, method, origin, params, resolution); - } else if(mResolverPtr->HasComRpcRequestSupport(method)) { - result = ProcessComRpcRequest(context, alias, method, params, origin, resolution); - } else { - // Check if includeContext is enabled for this method - std::string finalParams = UpdateContext(context, method, params, origin); - LOGTRACE("Final Request params alias=%s Params = %s", alias.c_str(), finalParams.c_str()); - - result = mResolverPtr->CallThunderPlugin(alias, finalParams, resolution); - if (result != Core::ERROR_NONE) { - LOGERR("Failed to retrieve resolution from Thunder method %s", alias.c_str()); - ErrorUtils::CustomInternal("Failed with internal error", resolution); - } else { - if (resolution.empty()) { - resolution = "null"; - } - } - } - return result; - } - - string AppGatewayImplementation::UpdateContext(const Context &context, const string& method, const string& params, const string& origin, const bool& onlyAdditionalContext) { - // Check if includeContext is enabled for this method - std::string finalParams = params; - JsonValue additionalContext; - if (mResolverPtr->HasIncludeContext(method, additionalContext)) { - LOGTRACE("Method '%s' requires context inclusion", method.c_str()); - JsonObject paramsObj; - if (!paramsObj.FromString(params)) - { - // In json rpc params are optional - LOGWARN("Failed to parse original params as JSON: %s", params.c_str()); - } - if (onlyAdditionalContext) { - if (additionalContext.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - JsonObject contextWithOrigin = additionalContext.Object(); - contextWithOrigin["origin"] = origin; - JsonObject finalParamsObject; - finalParamsObject["params"] = paramsObj; - finalParamsObject["_additionalContext"] = contextWithOrigin; - finalParamsObject.ToString(finalParams); - } else { - LOGERR("Additional context is not a JSON object for method: %s", method.c_str()); - } - } else { - JsonObject contextObj; - contextObj["appId"] = context.appId; - contextObj["connectionId"] = context.connectionId; - contextObj["requestId"] = context.requestId; - paramsObj["context"] = contextObj; - paramsObj.ToString(finalParams); - } - } - return finalParams; - } - - uint32_t AppGatewayImplementation::ProcessComRpcRequest(const Context &context, const string& alias, const string& method, const string& params, const string& origin, string &resolution) { - uint32_t result = Core::ERROR_GENERAL; - Exchange::IAppGatewayRequestHandler *requestHandler = mService->QueryInterfaceByCallsign(alias); - if (requestHandler != nullptr) { - std::string finalParams = UpdateContext(context, method, params, origin, true); - if (Core::ERROR_NONE != requestHandler->HandleAppGatewayRequest(context, method, finalParams, resolution)) { - LOGERR("HandleAppGatewayRequest failed for callsign: %s", alias.c_str()); - if (resolution.empty()){ - ErrorUtils::CustomInternal("HandleAppGatewayRequest failed", resolution); - } - } else { - result = Core::ERROR_NONE; - } - requestHandler->Release(); - } else { - LOGERR("Bad configuration %s Not available with COM RPC", alias.c_str()); - ErrorUtils::NotAvailable(resolution); - } - - return result; - } - - - uint32_t AppGatewayImplementation::PreProcessEvent(const Context &context, const string& alias, const string &method, const string& origin, const string& params, - string &resolution) { - JsonObject params_obj; - if (params_obj.FromString(params)) { - bool resultValue; - // Use ObjectUtils::HasBooleanEntry and populate resultValue - if (ObjectUtils::HasBooleanEntry(params_obj, "listen", resultValue)) { - LOGTRACE("Event method '%s' with listen: %s", method.c_str(), resultValue ? "true" : "false"); - auto ret_value = HandleEvent(context, alias, method, origin, resultValue); - JsonObject returnResult; - returnResult["listening"] = resultValue; - returnResult["event"] = method; - returnResult.ToString(resolution); - return ret_value; - } else { - LOGERR("Event method '%s' missing required boolean 'listen' parameter", method.c_str()); - ErrorUtils::CustomBadRequest("Missing required boolean 'listen' parameter", resolution); - return Core::ERROR_BAD_REQUEST; - } - } else { - LOGERR("Event method '%s' called without parameters", method.c_str()); - ErrorUtils::CustomBadRequest("Event methods require parameters", resolution); - return Core::ERROR_BAD_REQUEST; - } - } - - Core::hresult AppGatewayImplementation::HandleEvent(const Context &context, const string &alias, const string &event, const string &origin, const bool listen) { - if (mAppNotifications == nullptr) { - mAppNotifications = mService->QueryInterfaceByCallsign(APP_NOTIFICATIONS_CALLSIGN); - if (mAppNotifications == nullptr) { - LOGERR("IAppNotifications interface not available"); - return Core::ERROR_GENERAL; - } - } - - return mAppNotifications->Subscribe(ContextUtils::ConvertAppGatewayToNotificationContext(context,origin), listen, alias, event); - } - - void AppGatewayImplementation::SendToLaunchDelegate(const Context& context, const string& payload) - { - if ( mInternalGatewayResponder==nullptr ) { - mInternalGatewayResponder = mService->QueryInterfaceByCallsign(INTERNAL_GATEWAY_CALLSIGN); - if (mInternalGatewayResponder == nullptr) { - LOGERR("Internal Responder not available Not available"); - return; - } - } - - mInternalGatewayResponder->Respond(context, payload); - - } - - bool AppGatewayImplementation::SetupAppGatewayAuthenticator() { - if ( mAuthenticator==nullptr ) { - mAuthenticator = mService->QueryInterfaceByCallsign(INTERNAL_GATEWAY_CALLSIGN); - if (mAuthenticator == nullptr) { - LOGERR("AppGateway Authenticator not available"); - return false; - } - } - return true; - } - - // Helper: read a string key from a JSON file; returns empty if any step fails. - static std::string ReadJsonStringKey(const std::string& filePath, const std::string& key, const char* tag) { - if (filePath.empty()) { - return ""; - } - std::ifstream file(filePath); - if (!file.is_open()) { - LOGINFO("%s file not found: %s", tag, filePath.c_str()); - return ""; - } - std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - file.close(); - JsonObject json; - if (!json.FromString(content)) { - LOGERR("Failed to parse %s JSON: %s", tag, filePath.c_str()); - return ""; - } - if (!json.HasLabel(key.c_str())) { - LOGWARN("No '%s' field found in %s: %s", key.c_str(), tag, filePath.c_str()); - return ""; - } - std::string value = json[key.c_str()].String(); - LOGINFO("%s '%s' read: %s", tag, key.c_str(), value.c_str()); - return value; - } - - std::string AppGatewayImplementation::ReadCountryFromConfigFile() { - // Both config paths empty: rely on defaultCountryCode in resolutions.json later. - if (strlen(VENDOR_CONFIG_PATH) == 0 && strlen(BUILD_CONFIG_PATH) == 0) { - LOGINFO("Platform config paths not set; will use defaultCountryCode from resolutions.json if present"); - return ""; - } - - // Try vendor first, then build. - const std::string vendorPath = VENDOR_CONFIG_PATH; - const std::string buildPath = BUILD_CONFIG_PATH; - - std::string country = ReadJsonStringKey(vendorPath, "country", "Vendor config"); - if (!country.empty()) { - return country; - } - country = ReadJsonStringKey(buildPath, "country", "Build config"); - return country; // may be empty; caller handles fallback - } - - } // namespace Plugin -} // namespace WPEFramework - diff --git a/AppGateway/AppGatewayImplementation.h b/AppGateway/AppGatewayImplementation.h deleted file mode 100644 index ebd9dd9..0000000 --- a/AppGateway/AppGatewayImplementation.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include "Resolver.h" -#include -#include -#include -#include "ContextUtils.h" -#include -#include -#include - - -namespace WPEFramework { -namespace Plugin { - using Context = Exchange::GatewayContext; - class AppGatewayImplementation : public Exchange::IAppGatewayResolver, public Exchange::IConfiguration - { - - public: - AppGatewayImplementation(); - ~AppGatewayImplementation() override; - - // We do not allow this plugin to be copied !! - AppGatewayImplementation(const AppGatewayImplementation&) = delete; - AppGatewayImplementation& operator=(const AppGatewayImplementation&) = delete; - - BEGIN_INTERFACE_MAP(AppGatewayImplementation) - INTERFACE_ENTRY(Exchange::IConfiguration) - INTERFACE_ENTRY(Exchange::IAppGatewayResolver) - END_INTERFACE_MAP - - public: - Core::hresult Configure(Exchange::IAppGatewayResolver::IStringIterator *const &paths) override; - Core::hresult Resolve(const Context& context, const string& origin ,const string& method, const string& params, string& result) override; - - // IConfiguration interface - uint32_t Configure(PluginHost::IShell* service) override; - - private: - - class EXTERNAL RespondJob : public Core::IDispatch - { - protected: - RespondJob(AppGatewayImplementation *parent, - const Context& context, - const std::string& payload, - const std::string& destination - ) - : mParent(*parent), mPayload(payload), mContext(context), mDestination(destination) - { - } - - public: - RespondJob() = delete; - RespondJob(const RespondJob &) = delete; - RespondJob &operator=(const RespondJob &) = delete; - ~RespondJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayImplementation *parent, - const Context& context, const std::string& payload, const std::string& origin) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, context, payload, origin))); - } - virtual void Dispatch() - { - if(ContextUtils::IsOriginGateway(mDestination)) { - mParent.ReturnMessageInSocket(mContext, std::move(mPayload)); - } else { - mParent.SendToLaunchDelegate(mContext, std::move(mPayload)); - } - - } - - private: - AppGatewayImplementation &mParent; - const std::string mPayload; - const Context mContext; - const std::string mDestination; - }; - - Core::hresult HandleEvent(const Context &context, const string &alias, const string &event, const string &origin, const bool listen); - - void ReturnMessageInSocket(const Context& context, const string payload ) { - if (mAppGatewayResponder==nullptr) { - mAppGatewayResponder = mService->QueryInterface(); - } - - if (mAppGatewayResponder == nullptr) { - LOGERR("AppGateway Responder not available"); - return; - } - if (Core::ERROR_NONE != mAppGatewayResponder->Respond(context, payload)) { - LOGERR("Failed to Respond in Gateway"); - } - } - - PluginHost::IShell* mService; - ResolverPtr mResolverPtr; - Exchange::IAppNotifications *mAppNotifications; // Shared pointer to AppNotifications - Exchange::IAppGatewayResponder *mAppGatewayResponder; - Exchange::IAppGatewayResponder *mInternalGatewayResponder; // Shared pointer to InternalGatewayResponder - Exchange::IAppGatewayAuthenticator *mAuthenticator; // Shared pointer to Authenticator - uint32_t InitializeResolver(); - uint32_t InitializeWebsocket(); - uint32_t ProcessComRpcRequest(const Context &context, const string& alias, const string& method, const string& params, const string& origin, string &resolution); - uint32_t PreProcessEvent(const Context &context, const string& alias, const string &method, const string& origin, const string& params, string &resolution); - string UpdateContext(const Context &context, const string& method, const string& params, const string& origin, const bool& onlyAdditionalContext = false); - Core::hresult InternalResolve(const Context &context, const string &method, const string ¶ms, const string &origin, string& resolution); - Core::hresult FetchResolvedData(const Context &context, const string &method, const string ¶ms, const string &origin, string& resolution); - Core::hresult InternalResolutionConfigure(std::vector&& configPaths); - bool SetupAppGatewayAuthenticator(); - void SendToLaunchDelegate(const Context& context, const string& payload); - std::string ReadCountryFromConfigFile(); - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/AppGateway/AppGatewayResponderImplementation.cpp b/AppGateway/AppGatewayResponderImplementation.cpp deleted file mode 100644 index 9daec28..0000000 --- a/AppGateway/AppGatewayResponderImplementation.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#include -#include -#include -#include "AppGatewayResponderImplementation.h" -#include "UtilsLogging.h" -#include "UtilsConnections.h" -#include "UtilsCallsign.h" -#include - -// App Gateway is only available via local connections, -// so we can use a simple in-memory registry to track connection IDs and their associated app IDs. -#define APPGATEWAY_SOCKET_ADDRESS "127.0.0.1:3473" -#define DEFAULT_CONFIG_PATH "/etc/app-gateway/resolution.base.json" - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(AppGatewayResponderImplementation, 1, 0, 0); - - AppGatewayResponderImplementation::AppGatewayResponderImplementation() - : mService(nullptr), - mWsManager(), - mAuthenticator(nullptr), - mResolver(nullptr), - mConnectionStatusImplLock(), - mEnhancedLoggingEnabled(false) - { - LOGINFO("AppGatewayResponderImplementation constructor"); -#ifdef ENABLE_APP_GATEWAY_AUTOMATION - #ifdef APP_GATEWAY_ENHANCED_LOGGING_INDICATOR - struct stat buffer; - mEnhancedLoggingEnabled = (stat(APP_GATEWAY_ENHANCED_LOGGING_INDICATOR, &buffer) == 0); - LOGINFO("Enhanced logging enabled: %s (indicator: %s)", mEnhancedLoggingEnabled ? "true" : "false", APP_GATEWAY_ENHANCED_LOGGING_INDICATOR); - #endif -#endif - } - - AppGatewayResponderImplementation::~AppGatewayResponderImplementation() - { - LOGINFO("AppGatewayResponderImplementation destructor"); - if (nullptr != mService) - { - mService->Release(); - mService = nullptr; - } - - if (nullptr != mResolver) - { - mResolver->Release(); - mResolver = nullptr; - } - - if (nullptr != mAuthenticator) - { - mAuthenticator->Release(); - mAuthenticator = nullptr; - } - - } - - uint32_t AppGatewayResponderImplementation::Configure(PluginHost::IShell *shell) - { - LOGINFO("Configuring AppGatewayResponderImplementation"); - uint32_t result = Core::ERROR_NONE; - ASSERT(shell != nullptr); - mService = shell; - mService->AddRef(); - result = InitializeWebsocket(); - - return result; - } - - uint32_t AppGatewayResponderImplementation::InitializeWebsocket(){ - // Initialize WebSocket server - WebSocketConnectionManager::Config config(APPGATEWAY_SOCKET_ADDRESS); - std::string configLine = mService->ConfigLine(); - Core::OptionalType error; - if (config.FromString(configLine, error) == false) - { - LOGERR("Failed to parse config line, error: '%s', config line: '%s'.", - (error.IsSet() ? error.Value().Message().c_str() : "Unknown"), - configLine.c_str()); - } - - LOGINFO("Connector: %s", config.Connector.Value().c_str()); - Core::NodeId source(config.Connector.Value().c_str()); - LOGINFO("Parsed port: %d", source.PortNumber()); - mWsManager.SetMessageHandler( - [this](const std::string &method, const std::string ¶ms, const int requestId, const uint32_t connectionId) - { - Core::IWorkerPool::Instance().Submit(WsMsgJob::Create(this, method, params, requestId, connectionId)); - }); - - mWsManager.SetAuthHandler( - [this](const uint32_t connectionId, const std::string &token) -> bool - { - string sessionId = Utils::ResolveQuery(token, "session"); - if (sessionId.empty()) - { - LOGERR("No session token provided"); - return false; - } - - if ( mAuthenticator==nullptr ) { - mAuthenticator = mService->QueryInterfaceByCallsign(GATEWAY_AUTHENTICATOR_CALLSIGN); - if (mAuthenticator == nullptr) { - LOGERR("Authenticator Not available"); - return false; - } - } - - string appId; - if (Core::ERROR_NONE == mAuthenticator->Authenticate(sessionId,appId)) { - LOGTRACE("APP ID %s", appId.c_str()); - mAppIdRegistry.Add(connectionId, appId); - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Check if this is the automation client - #ifdef AUTOMATION_APP_ID - if (appId == AUTOMATION_APP_ID) { - mWsManager.SetAutomationId(connectionId); - LOGINFO("Automation server connected with ID: %d, appId: %s", connectionId, appId.c_str()); - } - #endif - #endif - - Core::IWorkerPool::Instance().Submit(ConnectionStatusNotificationJob::Create(this, connectionId, appId, true)); - - return true; - } - - return false; - }); - - mWsManager.SetDisconnectHandler( - [this](const uint32_t connectionId) - { - LOGINFO("Connection disconnected: %d", connectionId); - string appId; - if (!mAppIdRegistry.Get(connectionId, appId)) { - LOGERR("No App ID found for connection %d during disconnect", connectionId); - } else { - LOGINFO("App ID %s found for connection %d during disconnect", appId.c_str(), connectionId); - Core::IWorkerPool::Instance().Submit(ConnectionStatusNotificationJob::Create(this, connectionId, appId, false)); - } - - mAppIdRegistry.Remove(connectionId); - Exchange::IAppNotifications* appNotifications = mService->QueryInterfaceByCallsign(APP_NOTIFICATIONS_CALLSIGN); - if (appNotifications != nullptr) { - if (Core::ERROR_NONE != appNotifications->Cleanup(connectionId, APP_GATEWAY_CALLSIGN)) { - LOGERR("AppNotifications Cleanup failed for connectionId: %d", connectionId); - } - appNotifications->Release(); - appNotifications = nullptr; - } - } - ); - mWsManager.Start(source); - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayResponderImplementation::Respond(const Context& context, const string& payload) - { - Core::IWorkerPool::Instance().Submit(RespondJob::Create(this, context.connectionId, context.requestId, payload)); - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayResponderImplementation::Emit(const Context& context /* @in */, - const string& method /* @in */, const string& payload /* @in @opaque */) { - Core::IWorkerPool::Instance().Submit(EmitJob::Create(this, context.connectionId, method, payload)); - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayResponderImplementation::Request(const uint32_t connectionId /* @in */, - const uint32_t id /* @in */, const string& method /* @in */, const string& params /* @in @opaque */) { - Core::IWorkerPool::Instance().Submit(RequestJob::Create(this, connectionId, id, method, params)); - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayResponderImplementation::GetGatewayConnectionContext(const uint32_t connectionId /* @in */, - const string& contextKey /* @in */, - string& contextValue /* @out */) { - // TODO add support for jsonrpc compliance in later versions - return Core::ERROR_NONE; - } - - - void AppGatewayResponderImplementation::DispatchWsMsg(const std::string &method, - const std::string ¶ms, - const uint32_t requestId, - const uint32_t connectionId) - { - std::string resolution; - string appId; - - if (mAppIdRegistry.Get(connectionId, appId)) { - - if (mEnhancedLoggingEnabled) { - LOGDBG("%s-->[[a-%d-%d]] method=%s, params=%s", - appId.c_str(),connectionId, requestId, method.c_str(), params.c_str()); - } - // App Id is available - Context context = { - requestId, - connectionId, - appId - }; - - if (mResolver == nullptr) { - mResolver = mService->QueryInterface(); - } - - if (mResolver == nullptr) { - LOGERR("Resolver interface not available"); - return; - } - - string resolution; - if (Core::ERROR_NONE != mResolver->Resolve(context, APP_GATEWAY_CALLSIGN, method, params, resolution)) { - LOGERR("Resolver Failure"); - } - } else { - LOGERR("No App ID found for connection %d. Terminate connection", connectionId); - mWsManager.Close(connectionId); - } - } - - - Core::hresult AppGatewayResponderImplementation::Register(Exchange::IAppGatewayResponder::INotification *notification) - { - ASSERT (nullptr != notification); - - Core::SafeSyncType lock(mConnectionStatusImplLock); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mConnectionStatusNotification.begin(), mConnectionStatusNotification.end(), notification) == mConnectionStatusNotification.end()) - { - LOGINFO("Register notification"); - mConnectionStatusNotification.push_back(notification); - notification->AddRef(); - } - - return Core::ERROR_NONE; - } - - Core::hresult AppGatewayResponderImplementation::Unregister(Exchange::IAppGatewayResponder::INotification *notification ) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - Core::SafeSyncType lock(mConnectionStatusImplLock); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mConnectionStatusNotification.begin(), mConnectionStatusNotification.end(), notification); - if (itr != mConnectionStatusNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mConnectionStatusNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - return status; - } - - void AppGatewayResponderImplementation::OnConnectionStatusChanged(const string& appId, const uint32_t connectionId, const bool connected) - { - Core::SafeSyncType lock(mConnectionStatusImplLock); - for (auto& notification : mConnectionStatusNotification) - { - notification->OnAppConnectionChanged(appId, connectionId, connected); - } - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Notify automation server of connection status change - mWsManager.UpdateConnection(connectionId, appId, connected); - #endif - } - - } // namespace Plugin -} // namespace WPEFramework diff --git a/AppGateway/AppGatewayResponderImplementation.h b/AppGateway/AppGatewayResponderImplementation.h deleted file mode 100644 index e05b664..0000000 --- a/AppGateway/AppGatewayResponderImplementation.h +++ /dev/null @@ -1,320 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include "WsManager.h" -#include -#include -#include "ContextUtils.h" -#include -#include -#include - - -namespace WPEFramework { -namespace Plugin { - using Context = Exchange::GatewayContext; - class AppGatewayResponderImplementation : public Exchange::IConfiguration, public Exchange::IAppGatewayResponder - { - - public: - AppGatewayResponderImplementation(); - ~AppGatewayResponderImplementation() override; - - // We do not allow this plugin to be copied !! - AppGatewayResponderImplementation(const AppGatewayResponderImplementation&) = delete; - AppGatewayResponderImplementation& operator=(const AppGatewayResponderImplementation&) = delete; - - BEGIN_INTERFACE_MAP(AppGatewayResponderImplementation) - INTERFACE_ENTRY(Exchange::IConfiguration) - INTERFACE_ENTRY(Exchange::IAppGatewayResponder) - END_INTERFACE_MAP - - public: - Core::hresult Respond(const Context& context, const string& payload) override; - Core::hresult Emit(const Context& context /* @in */, - const string& method /* @in */, const string& payload /* @in @opaque */) override; - Core::hresult Request(const uint32_t connectionId /* @in */, - const uint32_t id /* @in */, const string& method /* @in */, const string& params /* @in @opaque */) override; - Core::hresult GetGatewayConnectionContext(const uint32_t connectionId /* @in */, - const string& contextKey /* @in */, - string& contextValue /* @out */) override; - - virtual Core::hresult Register(Exchange::IAppGatewayResponder::INotification *notification) override; - virtual Core::hresult Unregister(Exchange::IAppGatewayResponder::INotification *notification) override; - - virtual void OnConnectionStatusChanged(const string& appId, const uint32_t connectionId, const bool connected); - - // IConfiguration interface - uint32_t Configure(PluginHost::IShell* service) override; - - private: - class EXTERNAL WsMsgJob : public Core::IDispatch - { - protected: - WsMsgJob(AppGatewayResponderImplementation *parent, - const std::string& method, - const std::string& params, - const uint32_t requestId, - const uint32_t connectionId) - : mParent(*parent), mMethod(method), mParams(params), mRequestId(requestId), mConnectionId(connectionId) - { - } - - public: - WsMsgJob() = delete; - WsMsgJob(const WsMsgJob &) = delete; - WsMsgJob &operator=(const WsMsgJob &) = delete; - ~WsMsgJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayResponderImplementation *parent, - const std::string& method, const std::string& params, const uint32_t requestId, - const uint32_t connectionId) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, method, params, requestId, connectionId))); - } - virtual void Dispatch() - { - mParent.DispatchWsMsg(mMethod, mParams, mRequestId, mConnectionId); - } - - private: - AppGatewayResponderImplementation &mParent; - const std::string mMethod; - const std::string mParams; - const uint32_t mRequestId; - const uint32_t mConnectionId; - }; - - class EXTERNAL RespondJob : public Core::IDispatch - { - protected: - RespondJob(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, - const uint32_t requestId, - const std::string& payload - ) - : mParent(*parent), mPayload(payload), mRequestId(requestId), mConnectionId(connectionId) - { - } - - public: - RespondJob() = delete; - RespondJob(const RespondJob &) = delete; - RespondJob &operator=(const RespondJob &) = delete; - ~RespondJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, const uint32_t requestId, const std::string& payload) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, connectionId, requestId, payload))); - } - virtual void Dispatch() - { - mParent.ReturnMessageInSocket(mConnectionId, mRequestId, mPayload); - } - - private: - AppGatewayResponderImplementation &mParent; - const std::string mPayload; - const uint32_t mRequestId; - const uint32_t mConnectionId; - }; - - class EXTERNAL EmitJob : public Core::IDispatch - { - protected: - EmitJob(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, - const std::string& designator, - const std::string& payload - ) - : mParent(*parent), mPayload(payload), mDesignator(designator), mConnectionId(connectionId) - { - } - - public: - EmitJob() = delete; - EmitJob(const EmitJob &) = delete; - EmitJob &operator=(const EmitJob &) = delete; - ~EmitJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, const std::string& designator, const std::string& payload) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, connectionId, designator, payload))); - } - virtual void Dispatch() - { - mParent.mWsManager.DispatchNotificationToConnection(mConnectionId, mPayload, mDesignator); - } - - private: - AppGatewayResponderImplementation &mParent; - const std::string mPayload; - const std::string mDesignator; - const uint32_t mConnectionId; - }; - - class EXTERNAL RequestJob : public Core::IDispatch - { - protected: - RequestJob(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, - const uint32_t requestId, - const std::string& designator, - const std::string& payload - ) - : mParent(*parent), mPayload(payload), mDesignator(designator), mConnectionId(connectionId), mRequestId(requestId) - { - } - - public: - RequestJob() = delete; - RequestJob(const RequestJob &) = delete; - RequestJob &operator=(const RequestJob &) = delete; - ~RequestJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, const uint32_t mRequestId, const std::string& designator, const std::string& payload) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, connectionId, mRequestId, designator, payload))); - } - virtual void Dispatch() - { - mParent.mWsManager.SendRequestToConnection(mConnectionId, mDesignator, mRequestId, mPayload); - } - - private: - AppGatewayResponderImplementation &mParent; - const std::string mPayload; - const std::string mDesignator; - const uint32_t mConnectionId; - const uint32_t mRequestId; - }; - - class EXTERNAL ConnectionStatusNotificationJob : public Core::IDispatch - { - protected: - ConnectionStatusNotificationJob(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, - const std::string& appId, - const bool connected - ) - : mParent(*parent), mConnectionId(connectionId), mAppId(appId), mConnected(connected) - { - } - - public: - ConnectionStatusNotificationJob() = delete; - ConnectionStatusNotificationJob(const ConnectionStatusNotificationJob &) = delete; - ConnectionStatusNotificationJob &operator=(const ConnectionStatusNotificationJob &) = delete; - ~ConnectionStatusNotificationJob() - { - } - - public: - static Core::ProxyType Create(AppGatewayResponderImplementation *parent, - const uint32_t connectionId, const std::string& appId, const bool connected) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, connectionId, appId, connected))); - } - virtual void Dispatch() - { - mParent.OnConnectionStatusChanged(mAppId, mConnectionId, mConnected); - } - - private: - AppGatewayResponderImplementation &mParent; - const uint32_t mConnectionId; - const std::string mAppId; - const bool mConnected; - }; - - - class AppIdRegistry{ - public: - void Add(const uint32_t connectionId, const std::string& appId) { - std::lock_guard lock(mAppIdMutex); - mAppIdMap[connectionId] = appId; - } - - void Remove(const uint32_t connectionId) { - std::lock_guard lock(mAppIdMutex); - mAppIdMap.erase(connectionId); - } - - bool Get(const uint32_t connectionId, string& appId) { - std::lock_guard lock(mAppIdMutex); - auto it = mAppIdMap.find(connectionId); - if (it != mAppIdMap.end()) { - appId = it->second; - return true; - } - return false; - } - - - private: - std::unordered_map mAppIdMap; - std::mutex mAppIdMutex; - }; - - void DispatchWsMsg(const std::string& method, - const std::string& params, - const uint32_t requestId, - const uint32_t connectionId); - - - void ReturnMessageInSocket(const uint32_t connectionId, const int requestId, const string payload ) { - if (mEnhancedLoggingEnabled) { - LOGDBG("<--[[a-%d-%d]] payload=%s", - connectionId, requestId, payload.c_str()); - } - - // Send response back to client - mWsManager.SendMessageToConnection(connectionId, payload, requestId); - } - - PluginHost::IShell* mService; - WebSocketConnectionManager mWsManager; - Exchange::IAppGatewayAuthenticator *mAuthenticator; // Shared pointer to Authenticator - Exchange::IAppGatewayResolver *mResolver; // Shared pointer to InternalGatewayResolver - AppIdRegistry mAppIdRegistry; - uint32_t InitializeWebsocket(); - mutable Core::CriticalSection mConnectionStatusImplLock; - std::list mConnectionStatusNotification; - bool mEnhancedLoggingEnabled; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/AppGateway/CMakeLists.txt b/AppGateway/CMakeLists.txt deleted file mode 100644 index 3ce5bd5..0000000 --- a/AppGateway/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME AppGateway) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(VERSION_MAJOR 1) -set(VERSION_MINOR 0) -set(VERSION_PATCH 0) - -add_compile_definitions(APPGATEWAY_MAJOR_VERSION=${VERSION_MAJOR}) -add_compile_definitions(APPGATEWAY_MINOR_VERSION=${VERSION_MINOR}) -add_compile_definitions(APPGATEWAY_PATCH_VERSION=${VERSION_PATCH}) - -set(MODULE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) - -set(PLUGIN_APPGATEWAY_STARTUPORDER "" CACHE STRING "To configure startup order of AppGateway plugin") -set(PLUGIN_APPGATEWAY_AUTOSTART "false" CACHE STRING "Automatically start AppGateway plugin") - -message("Setup ${MODULE_NAME} v${MODULE_VERSION}") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - AppGateway.cpp - AppGatewayImplementation.cpp - AppGatewayResponderImplementation.cpp - Resolver.cpp - Module.cpp) - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) -target_include_directories(${MODULE_NAME} PRIVATE ./resolutions) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - -# Add platform-specific paths -if(BUILD_CONFIG_PATH) - target_compile_definitions(${MODULE_NAME} PRIVATE BUILD_CONFIG_PATH="${BUILD_CONFIG_PATH}") -endif() - -if(VENDOR_CONFIG_PATH) - target_compile_definitions(${MODULE_NAME} PRIVATE VENDOR_CONFIG_PATH="${VENDOR_CONFIG_PATH}") -endif() - -# Add App Gateway Automation definitions if enabled -if(ENABLE_APP_GATEWAY_AUTOMATION) - target_compile_definitions(${MODULE_NAME} PRIVATE ENABLE_APP_GATEWAY_AUTOMATION) - if(AUTOMATION_APP_ID) - target_compile_definitions(${MODULE_NAME} PRIVATE AUTOMATION_APP_ID=${AUTOMATION_APP_ID}) - endif() - if(APP_GATEWAY_ENHANCED_LOGGING_INDICATOR) - target_compile_definitions(${MODULE_NAME} PRIVATE APP_GATEWAY_ENHANCED_LOGGING_INDICATOR=${APP_GATEWAY_ENHANCED_LOGGING_INDICATOR}) - endif() -endif() - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -# To error any missing links -target_link_options(${MODULE_NAME} PRIVATE -Wl,-z,defs) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resolutions/resolution.base.json - DESTINATION "/etc/app-gateway/") - -write_config(${PLUGIN_NAME}) diff --git a/AppGateway/Module.h b/AppGateway/Module.h deleted file mode 100755 index 5f961de..0000000 --- a/AppGateway/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_AppGateway -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/AppGateway/Resolver.cpp b/AppGateway/Resolver.cpp deleted file mode 100644 index ed04da5..0000000 --- a/AppGateway/Resolver.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#include "Resolver.h" -#include -#include -#include "UtilsLogging.h" -#include "StringUtils.h" -#include "UtilsJsonrpcDirectLink.h" -#include - - -namespace WPEFramework -{ - namespace Plugin - { - - Resolver::Resolver(PluginHost::IShell *shell) - : mService(shell), mResolutions(), mMutex() - { - LOGINFO("[Resolver] Constructor - configurations will be loaded via LoadConfig"); - } - - Resolver::~Resolver() - { - LOGINFO("Call Resolver destructor"); - if (nullptr != mService) - { - mService->Release(); - mService = nullptr; - } - } - - bool Resolver::LoadConfig(const std::string &path) - { - std::ifstream file(path); - if (!file.is_open()) - { - LOGERR("[Resolver] Failed to open config file: %s", path.c_str()); - return false; - } - - // Use ConfigContainer for direct JSON parsing from file - ConfigContainer config; - WPEFramework::Core::OptionalType error; - - // Read file content efficiently - std::string jsonContent((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); - file.close(); - - if (!config.IElement::FromString(jsonContent, error)) - { - LOGERR("[Resolver] Failed to parse JSON from: %s", path.c_str()); - if (error.IsSet()) - { - LOGERR(" - Error: %s", error.Value().Message().c_str()); - } - return false; - } - - // Direct access to resolutions via ConfigContainer - if (!config.Resolutions.IsSet()) - { - LOGERR("[Resolver] No 'resolutions' object in config file: %s", path.c_str()); - return false; - } - - // Acquire lock before modifying mResolutions - std::lock_guard lock(mMutex); - size_t loadedCount = 0; - size_t overriddenCount = 0; - - // Iterate through all resolution entries with optimized parsing - WPEFramework::Core::JSON::VariantContainer::Iterator it = config.Resolutions.Variants(); - while (it.Next()) - { - const std::string &key = StringUtils::toLower(it.Label()); - WPEFramework::Core::JSON::Variant resolutionVariant = it.Current(); - - if (resolutionVariant.IsSet() && !resolutionVariant.IsNull()) - { - // Create Resolution struct and populate using helper functions - Resolution r; - WPEFramework::Core::JSON::VariantContainer resolutionObj = resolutionVariant.Object(); - - // Use helper functions to extract all fields consistently - r.alias = ExtractStringField(resolutionObj, "alias"); - r.event = ExtractStringField(resolutionObj, "event"); - r.permissionGroup = ExtractStringField(resolutionObj, "permissionGroup"); - r.additionalContext = ExtractAdditionalContext(resolutionObj, "additionalContext"); - bool hasAdditionalContext = r.additionalContext.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT; - r.includeContext = ExtractBooleanField(resolutionObj, "includeContext", hasAdditionalContext); - r.useComRpc = ExtractBooleanField(resolutionObj, "useComRpc", hasAdditionalContext); - - LOGINFO("[Resolver] Loaded resolution for key: %s -> alias: %s, event: %s, permissionGroup: %s, includeContext: %s, useComRpc: %s", - key.c_str(), r.alias.c_str(), r.event.c_str(), r.permissionGroup.c_str(), - r.includeContext ? "true" : "false", r.useComRpc ? "true" : "false"); - - // Check if this resolution already exists (will be overridden) - if (mResolutions.find(key) != mResolutions.end()) - { - LOGTRACE("[Resolver] Overriding resolution for key: %s", key.c_str()); - overriddenCount++; - } - - mResolutions[key] = std::move(r); - loadedCount++; - } - } - - LOGINFO("[Resolver] Loaded %zu resolutions from %s (%zu new, %zu overridden). Total resolutions: %zu", - loadedCount, path.c_str(), loadedCount - overriddenCount, overriddenCount, mResolutions.size()); - - return true; - } - - void Resolver::ClearResolutions() - { - std::lock_guard lock(mMutex); - mResolutions.clear(); - LOGINFO("[Resolver] Cleared all resolutions"); - } - - bool Resolver::IsConfigured() - { - std::lock_guard lock(mMutex); - return !mResolutions.empty(); - } - - std::string Resolver::ResolveAlias(const std::string &key) - { - std::string lowerKey = StringUtils::toLower(key); - std::lock_guard lock(mMutex); - auto it = mResolutions.find(lowerKey); - if (it != mResolutions.end()) - { - return it->second.alias; - } - return {}; // return empty if not found - } - - void Resolver::ParseAlias(const std::string &alias, std::string &callsign, std::string &pluginMethod) - { - // Find last '.' in the string - size_t dotPos = alias.rfind('.'); - - if (dotPos != std::string::npos) - { - callsign = alias.substr(0, dotPos); // "org.rdk.UserSettings" - pluginMethod = alias.substr(dotPos + 1); // "getAudioDescription" - } - else - { - // Fallback: no dot found - callsign = alias; - pluginMethod = ""; - } - - LOGTRACE("[Resolver] Parsed alias '%s' -> callsign: '%s', method: '%s'", - alias.c_str(), callsign.c_str(), pluginMethod.c_str()); - } - - std::string Resolver::ExtractStringField(const WPEFramework::Core::JSON::VariantContainer &obj, const char *fieldName) - { - WPEFramework::Core::JSON::Variant field = obj[fieldName]; - if (field.IsSet() && !field.IsNull() && field.Content() == WPEFramework::Core::JSON::Variant::type::STRING) - { - return field.String(); - } - return ""; - } - - bool Resolver::ExtractBooleanField(const WPEFramework::Core::JSON::VariantContainer &obj, const char *fieldName, bool defaultValue) - { - WPEFramework::Core::JSON::Variant field = obj[fieldName]; - if (field.IsSet() && !field.IsNull() && field.Content() == WPEFramework::Core::JSON::Variant::type::BOOLEAN) - { - return field.Boolean(); - } - return defaultValue; - } - - JsonValue Resolver::ExtractAdditionalContext(JsonObject &obj, const char *fieldName) - { - return obj.Get(fieldName); - } - - Core::hresult Resolver::CallThunderPlugin(const std::string &alias, const std::string ¶ms, std::string &response) - { - if (mService == nullptr) - { - LOGERR("Shell service not set. Call setShell() first."); - return Core::ERROR_GENERAL; - } - - if (alias.empty()) - { - LOGERR("Empty alias provided"); - return Core::ERROR_GENERAL; - } - - std::string callsign; - std::string pluginMethod; - - // Parse the alias to extract callsign and method - ParseAlias(alias, callsign, pluginMethod); - - if (callsign.empty()) - { - LOGERR("Failed to parse callsign from alias: %s", alias.c_str()); - return Core::ERROR_GENERAL; - } - - if (pluginMethod.empty()) - { - LOGERR("No method found in alias: %s", alias.c_str()); - return Core::ERROR_GENERAL; - } - - auto thunderLink = Utils::GetThunderControllerClient(mService, callsign); - if (!thunderLink) - { - LOGERR("Failed to create JSONRPCDirectLink for callsign: %s", callsign.c_str()); - return Core::ERROR_GENERAL; - } - - Core::hresult result = thunderLink->Invoke(pluginMethod, params, response); - if (result != Core::ERROR_NONE) - { - LOGERR("Invoke failed for %s.%s, error code: %u", - callsign.c_str(), pluginMethod.c_str(), result); - } - return result; - } - - bool Resolver::HasEvent(const std::string &key) - { - std::lock_guard lock(mMutex); - std::string lowerKey = StringUtils::toLower(key); - auto it = mResolutions.find(lowerKey); - if (it != mResolutions.end()) - { - return !it->second.event.empty(); - } - return false; - } - - bool Resolver::HasIncludeContext(const std::string &key, JsonValue& additionalContext) - { - std::lock_guard lock(mMutex); - std::string lowerKey = StringUtils::toLower(key); - auto it = mResolutions.find(lowerKey); - if (it != mResolutions.end()) - { - if (it->second.additionalContext.IsSet()) { - additionalContext = it->second.additionalContext; - } - return it->second.includeContext; - } - return false; - } - - bool Resolver::HasComRpcRequestSupport(const std::string &key) { - std::string lowerKey = StringUtils::toLower(key); - std::lock_guard lock(mMutex); - auto it = mResolutions.find(lowerKey); - if (it != mResolutions.end()) - { - return it->second.useComRpc; - } - return false; - } - - bool Resolver::HasPermissionGroup(const std::string& key, std::string& permissionGroup ) - { - std::lock_guard lock(mMutex); - std::string lowerKey = StringUtils::toLower(key); - auto it = mResolutions.find(lowerKey); - if (it != mResolutions.end()) - { - permissionGroup = it->second.permissionGroup; - return !permissionGroup.empty(); - } - return false; - } - - } -} - diff --git a/AppGateway/Resolver.h b/AppGateway/Resolver.h deleted file mode 100644 index 1cac704..0000000 --- a/AppGateway/Resolver.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#pragma once - -#include "Module.h" -#include "UtilsLogging.h" -#include "StringUtils.h" -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - - // Configuration container for the entire resolutions file - class ConfigContainer : public WPEFramework::Core::JSON::Container - { - public: - ConfigContainer(const ConfigContainer &) = delete; - ConfigContainer &operator=(const ConfigContainer &) = delete; - - ConfigContainer() - : WPEFramework::Core::JSON::Container(), Resolutions() - { - Add(_T("resolutions"), &Resolutions); - } - - WPEFramework::Core::JSON::VariantContainer Resolutions; - }; - - // Struct holding resolution info - struct Resolution - { - std::string alias; - std::string event; - std::string permissionGroup; - JsonValue additionalContext; - bool includeContext = false; - bool useComRpc = false; - }; - - - - using namespace WPEFramework; - class Resolver - { - public: - Resolver(PluginHost::IShell *shell); - ~Resolver(); - - // Load resolutions from a JSON config file - bool LoadConfig(const std::string &path); - - // Clear all existing resolutions - void ClearResolutions(); - - // Check if resolver has been properly configured - bool IsConfigured(); - - std::string ResolveAlias(const std::string &request); - Core::hresult CallThunderPlugin(const std::string &alias, const std::string ¶ms, std::string &response); - - // New Method to check if given method has ComRPC request ability - bool HasComRpcRequestSupport(const std::string &key); - - // New method to check if the event field exists for a given key - bool HasEvent(const std::string &key); - - // New method to check if includeContext is enabled for a given key - bool HasIncludeContext(const std::string &key, JsonValue& additionalContext); - - // New method to check permission group is enabled - bool HasPermissionGroup(const std::string& key, std::string& permissionGroup ); - - private: - void ParseAlias(const std::string &alias, std::string &callsign, std::string &pluginMethod); - - // Helper function to extract string field from JSON variant with type checking - static std::string ExtractStringField(const WPEFramework::Core::JSON::VariantContainer &obj, const char *fieldName); - - // Helper function to extract boolean field from JSON variant with type checking - static bool ExtractBooleanField(const WPEFramework::Core::JSON::VariantContainer &obj, const char *fieldName, bool defaultValue = false); - JsonValue ExtractAdditionalContext(JsonObject &obj, const char *fieldName); - - - PluginHost::IShell *mService; - std::unordered_map mResolutions; - std::mutex mMutex; - }; - - using ResolverPtr = std::shared_ptr; - - } // namespace Plugin -} // namespace WPEFramework - diff --git a/AppGateway/resolutions/resolution.base.json b/AppGateway/resolutions/resolution.base.json deleted file mode 100644 index f12a888..0000000 --- a/AppGateway/resolutions/resolution.base.json +++ /dev/null @@ -1,270 +0,0 @@ -{ - "resolutions": { - "Localization.addAdditionalInfo": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.make": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.name": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.setName": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "localization.countryCode": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.setCountryCode": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "localization.timeZone": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.setTimeZone": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "localization.language": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.locale": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.setLocale": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "localization.preferredAudioLanguages": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.setPreferredAudioLanguages": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "voiceguidance.setEnabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "voiceguidance.setSpeed": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "accessibility.audioDescriptionSettings": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "accessibility.closedCaptions": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "accessibility.closedCaptionsSettings": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "audiodescriptions.enabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "audiodescriptions.setEnabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "accessibility.highContrastUI": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "closedcaptions.enabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "closedcaptions.setEnabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "closedcaptions.preferredLanguages": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "closedcaptions.setPreferredLanguages": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "voiceguidance.navigationHints": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "voiceguidance.setNavigationHints": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "voiceguidance.rate": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "voiceguidance.setRate": { - "alias": "org.rdk.FbSettings", - "useComRpc": true, - "permissionGroup": "org.rdk.permission.group.enhanced" - }, - "voiceguidance.enabled": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "voiceguidance.speed": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "accessibility.voiceGuidanceSettings": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "accessibility.voiceGuidance": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.network": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "localization.onLanguageChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onPresentationLanguageChanged" - }, - "localization.onLocaleChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onLocaleChanged" - }, - "localization.onPreferredAudioLanguagesChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onPreferredAudioLanguagesChanged" - }, - "accessibility.onAudioDescriptionSettingsChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onAudioDescriptionChanged" - }, - "audiodescriptions.onEnabledChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onAudioDescriptionsChanged" - }, - "accessibility.onHighContrastUIChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onHighContrastChanged" - }, - "closedcaptions.onEnabledChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onCaptionsChanged" - }, - "closedcaptions.onPreferredLanguagesChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onPreferredCaptionsLanguagesChanged" - }, - "accessibility.onClosedCaptionsSettingsChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onCaptionsChanged" - }, - "voiceguidance.onNavigationHintsChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onVoiceGuidanceHintsChanged" - }, - "voiceguidance.onRateChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onVoiceGuidanceRateChanged" - }, - "voiceguidance.onEnabledChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onVoiceGuidanceChanged" - }, - "voiceguidance.onSpeedChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onVoiceGuidanceRateChanged" - }, - "accessibility.onVoiceGuidanceSettingsChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onVoiceGuidanceChanged" - }, - "device.onNetworkChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onInternetStatusChange" - }, - "device.version": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "Localization.onCountryCodeChanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onCountryCodeChanged" - }, - "device.screenResolution": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.videoResolution": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.hdr": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.hdcp": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.audio": { - "alias": "org.rdk.FbSettings", - "useComRpc": true - }, - "device.onhdrchanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onDisplayConnectionChanged" - }, - "device.onhdcpchanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onDisplayConnectionChanged" - }, - "device.onvideoresolutionchanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onScreenResolutionChanged" - }, - "device.onscreenresolutionchanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.resolutionChanged" - }, - "device.onaudiochanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.audioFormatChanged" - }, - "device.ondevicenamechanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onFriendlyNameChanged" - }, - "device.onnamechanged": { - "alias": "org.rdk.FbSettings", - "event": "org.rdk.FbSettings.onFriendlyNameChanged" - } - } -} - - diff --git a/AppGateway/tests/CurlCmds.md b/AppGateway/tests/CurlCmds.md deleted file mode 100644 index 1cbe09e..0000000 --- a/AppGateway/tests/CurlCmds.md +++ /dev/null @@ -1,44 +0,0 @@ - - - -curl -d '{ - "jsonrpc": "2.0", - "id": 122, - "method": "Controller.1.activate", - "params": { "callsign": "org.rdk.AppGateway" } -}' http://127.0.0.1:9998/jsonrpc - - -curl -d '{ - "jsonrpc": "2.0", - "id": 122, - "method": "Controller.1.deactivate", - "params": { "callsign": "org.rdk.AppGateway" } -}' http://127.0.0.1:9998/jsonrpc - - -curl -d '{ - "jsonrpc": "2.0", - "id": 122, - "method": "org.rdk.AppGateway.1.resolve", - "params": { "context" : {"requestId" : 1, "connectionId" : 3, "appId" : "Peacock"}, - "method" : "Accessibility.audioDescriptionSettings" - } -}' http://127.0.0.1:9998/jsonrpc - -curl -d '{ - "jsonrpc": "2.0", - "id": 122, - "method": "org.rdk.AppGateway.1.resolve", - "params": { "context" : {"requestId" : 1, "connectionId" : 3, "appId" : "Peacock"}, - "method" : "Advertising.advertisingId", - "params" : {} - } -}' http://127.0.0.1:9998/jsonrpc - -curl -d '{ - "jsonrpc": "2.0", - "id": 122, - "method": "org.rdk.AppGateway.1.respond" -}' http://127.0.0.1:9998/jsonrpc - diff --git a/AppManager/AppManager.conf.in b/AppManager/AppManager.conf.in deleted file mode 100755 index 9c925c2..0000000 --- a/AppManager/AppManager.conf.in +++ /dev/null @@ -1,11 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.AppManager" -autostart = "@PLUGIN_APP_MANAGER_AUTOSTART@" -startuporder = "@PLUGIN_APP_MANAGER_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_APP_MANAGER_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) \ No newline at end of file diff --git a/AppManager/AppManager.config b/AppManager/AppManager.config deleted file mode 100755 index 1c35167..0000000 --- a/AppManager/AppManager.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart ${PLUGIN_APP_MANAGER_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.AppManager") - -if(PLUGIN_APP_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_APP_MANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_APP_MANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) \ No newline at end of file diff --git a/AppManager/AppManager.cpp b/AppManager/AppManager.cpp deleted file mode 100644 index 9084cc2..0000000 --- a/AppManager/AppManager.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "AppManager.h" - -const string WPEFramework::Plugin::AppManager::SERVICE_NAME = "org.rdk.AppManager"; - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - APP_MANAGER_API_VERSION_NUMBER_MAJOR, APP_MANAGER_API_VERSION_NUMBER_MINOR, APP_MANAGER_API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register AppManager module as wpeframework plugin - **/ - SERVICE_REGISTRATION(AppManager, APP_MANAGER_API_VERSION_NUMBER_MAJOR, APP_MANAGER_API_VERSION_NUMBER_MINOR, APP_MANAGER_API_VERSION_NUMBER_PATCH); - - AppManager* AppManager::_instance = nullptr; - - - AppManager::AppManager() : - mCurrentService(nullptr), - mConnectionId(0), - mAppManagerImpl(nullptr), - mAppManagerNotification(this), - mAppManagerConfigure(nullptr) - { - SYSLOG(Logging::Startup, (_T("AppManager Constructor"))); - if (nullptr == AppManager::_instance) - { - AppManager::_instance = this; - } - } - - AppManager::~AppManager() - { - SYSLOG(Logging::Shutdown, (string(_T("AppManager Destructor")))); - AppManager::_instance = nullptr; - } - - const string AppManager::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mAppManagerImpl); - ASSERT(0 == mConnectionId); - - SYSLOG(Logging::Startup, (_T("AppManager::Initialize: PID=%u"), getpid())); - - mCurrentService = service; - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - mCurrentService->Register(&mAppManagerNotification); - - if (nullptr == (mAppManagerImpl = mCurrentService->Root(mConnectionId, 5000, _T("AppManagerImplementation")))) - { - SYSLOG(Logging::Startup, (_T("AppManager::Initialize: object creation failed"))); - message = _T("AppManager plugin could not be initialised"); - } - else if (nullptr == (mAppManagerConfigure = mAppManagerImpl->QueryInterface())) - { - SYSLOG(Logging::Startup, (_T("AppManager::Initialize: did not provide a configuration interface"))); - message = _T("AppManager implementation did not provide a configuration interface"); - } - else - { - // Register for notifications - mAppManagerImpl->Register(&mAppManagerNotification); - // Invoking Plugin API register to wpeframework - Exchange::JAppManager::Register(*this, mAppManagerImpl); - - if (Core::ERROR_NONE != mAppManagerConfigure->Configure(mCurrentService)) - { - SYSLOG(Logging::Startup, (_T("AppManager::Initialize: could not be configured"))); - message = _T("AppManager could not be configured"); - } - } - } - else - { - SYSLOG(Logging::Startup, (_T("AppManager::Initialize: service is not valid"))); - message = _T("AppManager plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void AppManager::Deinitialize(PluginHost::IShell* service) - { - ASSERT(mCurrentService == service); - - SYSLOG(Logging::Shutdown, (string(_T("AppManager::Deinitialize")))); - - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - mCurrentService->Unregister(&mAppManagerNotification); - - if (nullptr != mAppManagerImpl) - { - mAppManagerImpl->Unregister(&mAppManagerNotification); - Exchange::JAppManager::Unregister(*this); - - if (nullptr != mAppManagerConfigure) - { - mAppManagerConfigure->Release(); - mAppManagerConfigure = nullptr; - } - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mAppManagerImpl->Release(); - - mAppManagerImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mCurrentService->Release(); - mCurrentService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("AppManager de-initialised")))); - } - - string AppManager::Information() const - { - // No additional info to report - return (string()); - } - - void AppManager::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) - { - ASSERT(nullptr != mCurrentService); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mCurrentService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/AppManager/AppManager.h b/AppManager/AppManager.h deleted file mode 100755 index a9376d4..0000000 --- a/AppManager/AppManager.h +++ /dev/null @@ -1,143 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - - class AppManager: public PluginHost::IPlugin, public PluginHost::JSONRPC - { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IAppManager::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(AppManager* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IAppManager::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - LOGINFO("AppManager Notification Activated"); - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - LOGINFO("AppManager Notification Deactivated"); - _parent.Deactivated(connection); - } - - void OnAppInstalled(const string& appId, const string& version) override - { - LOGINFO("AppManager on OnAppInstalled" ); - Exchange::JAppManager::Event::OnAppInstalled(_parent, appId,version); - } - - void OnAppUninstalled(const string& appId)override - { - LOGINFO("AppManager on OnAppUninstalled" ); - Exchange::JAppManager::Event::OnAppUninstalled(_parent, appId); - } - - void OnAppLifecycleStateChanged(const string& appId, const string& appInstanceId,const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) override - { - LOGINFO("AppManager on onAppLifecycleStateChanged"); - Exchange::JAppManager::Event::OnAppLifecycleStateChanged(_parent, appId,appInstanceId,newState,oldState,errorReason); - } - - void OnAppLaunchRequest(const string& appId, const string& intent, const string& source) override - { - LOGINFO("AppManager on OnAppLaunchRequest" ); - Exchange::JAppManager::Event::OnAppLaunchRequest(_parent, appId,intent,source); - } - - void OnAppUnloaded(const string& appId, const string& appInstanceId) override - { - LOGINFO("AppManager on OnAppUnloaded" ); - Exchange::JAppManager::Event::OnAppUnloaded(_parent, appId ,appInstanceId); - } - - private: - AppManager& _parent; - }; - - public: - AppManager(const AppManager&) = delete; - AppManager& operator=(const AppManager&) = delete; - - AppManager(); - virtual ~AppManager(); - - BEGIN_INTERFACE_MAP(AppManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IAppManager, mAppManagerImpl) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* mCurrentService{}; - uint32_t mConnectionId{}; - Exchange::IAppManager* mAppManagerImpl{}; - Core::Sink mAppManagerNotification; - Exchange::IConfiguration* mAppManagerConfigure; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static AppManager* _instance; - }; - -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/AppManager/AppManagerImplementation.cpp b/AppManager/AppManagerImplementation.cpp deleted file mode 100755 index e454648..0000000 --- a/AppManager/AppManagerImplementation.cpp +++ /dev/null @@ -1,1669 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include /* for std::setw, std::setfill */ -#include "AppManagerImplementation.h" -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include "AppManagerTelemetryReporting.h" -#endif - -#define TIME_DATA_SIZE 200 -static bool sRunning = false; - -namespace WPEFramework { -namespace Plugin { - -SERVICE_REGISTRATION(AppManagerImplementation, 1, 0); -AppManagerImplementation* AppManagerImplementation::_instance = nullptr; - -AppManagerImplementation::AppManagerImplementation() -: mAdminLock() -, mAppManagerNotification() -, mLifecycleInterfaceConnector(nullptr) -, mPersistentStoreRemoteStoreObject(nullptr) -, mPackageManagerHandlerObject(nullptr) -, mPackageManagerInstallerObject(nullptr) -, mCurrentservice(nullptr) -, mPackageManagerNotification(*this) -, mAppManagerWorkerThread() -{ - LOGINFO("Create AppManagerImplementation Instance"); - if (nullptr == AppManagerImplementation::_instance) - { - AppManagerImplementation::_instance = this; - } -} - -AppManagerImplementation* AppManagerImplementation::getInstance() -{ - return _instance; -} - -AppManagerImplementation::~AppManagerImplementation() -{ - LOGINFO("Delete AppManagerImplementation Instance"); - _instance = nullptr; - sRunning = false; - mAppRequestListCV.notify_all(); - if (mAppManagerWorkerThread.joinable()) - { - mAppManagerWorkerThread.join(); - LOGINFO("App Manager Worker Thread joined successfully"); - } - - if (nullptr != mLifecycleInterfaceConnector) - { - mLifecycleInterfaceConnector->releaseLifecycleManagerRemoteObject(); - delete mLifecycleInterfaceConnector; - mLifecycleInterfaceConnector = nullptr; - } - releasePersistentStoreRemoteStoreObject(); - releasePackageManagerObject(); - releaseStorageManagerRemoteObject(); - if (nullptr != mCurrentservice) - { - mCurrentservice->Release(); - mCurrentservice = nullptr; - } -} - -/** - * Register a notification callback - */ -Core::hresult AppManagerImplementation::Register(Exchange::IAppManager::INotification *notification) -{ - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - if (std::find(mAppManagerNotification.begin(), mAppManagerNotification.end(), notification) == mAppManagerNotification.end()) - { - LOGINFO("Register notification"); - mAppManagerNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; -} - -void AppManagerImplementation::AppManagerWorkerThread(void) -{ - while (sRunning) - { - std::shared_ptr request = nullptr; - std::unique_lock lock(mAppManagerLock); - mAppRequestListCV.wait(lock, [this] {return !mAppRequestList.empty() || !sRunning;}); - - if (!mAppRequestList.empty() && sRunning) - { - Core::hresult status = Core::ERROR_GENERAL; - request = mAppRequestList.front(); - mAppRequestList.pop_front(); - - if (request != nullptr) - { - CurrentAction action = request->mRequestAction; - - switch (action) - { - case APP_ACTION_LAUNCH: - case APP_ACTION_PRELOAD: - { - if (nullptr != request->mRequestParam) - { - if (auto appRequestParam = std::static_pointer_cast(request->mRequestParam)) - { - string appId = appRequestParam->appId; - PackageInfo packageData; - Exchange::IPackageHandler::LockReason lockReason = Exchange::IPackageHandler::LockReason::LAUNCH; - - status = packageLock(appId, packageData, lockReason); - if (status == Core::ERROR_NONE) - { - WPEFramework::Exchange::RuntimeConfig runtimeConfig = packageData.configMetadata; - runtimeConfig.unpackedPath = packageData.unpackedPath; - getCustomValues(runtimeConfig); - string launchArgs = appRequestParam->launchArgs; - - if (action == APP_ACTION_LAUNCH) - { - status = mLifecycleInterfaceConnector->launch(appId, appRequestParam->intent, launchArgs, runtimeConfig); - LOGINFO("Application Launch from thread returns with status %d", status); - - if (status != Core::ERROR_NONE) - { - LOGERR("launch failed status %d", status); - } - } - else if (action == APP_ACTION_PRELOAD) - { - string errorReason; - status = mLifecycleInterfaceConnector->preLoadApp(appId, launchArgs, runtimeConfig, errorReason); - LOGINFO("Application preLoad from thread returns with status %d error %s", status, errorReason.c_str()); - - if ((!errorReason.empty()) || (status != Core::ERROR_NONE)) - { - LOGERR("preLoadApp failed reason %s status %d", errorReason.c_str(), status); - } - } - } - else - { - bool installed = false; - - IsInstalled(appId, installed); - LOGERR("Failed to PackageManager Lock %s installed %d", appId.c_str(), installed); - handleOnAppLifecycleStateChanged(appId, "", - Exchange::IAppManager::APP_STATE_UNKNOWN, - Exchange::IAppManager::APP_STATE_UNLOADED, - (installed == true)?Exchange::IAppManager::APP_ERROR_PACKAGE_LOCK: Exchange::IAppManager::APP_ERROR_NOT_INSTALLED); - } - } - } - } - break; /*APP_ACTION_LAUNCH | APP_ACTION_PRELOAD*/ - - default: - { - LOGERR("action type is invalid"); - } - break; /* defult*/ - } - } - } - } - { - std::lock_guard lock(mAppManagerLock); - mAppRequestList.clear(); - } -} - -/** - * Unregister a notification callback - */ -Core::hresult AppManagerImplementation::Unregister(Exchange::IAppManager::INotification *notification ) -{ - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - auto itr = std::find(mAppManagerNotification.begin(), mAppManagerNotification.end(), notification); - if (itr != mAppManagerNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mAppManagerNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; -} - -void AppManagerImplementation::dispatchEvent(EventNames event, const JsonObject ¶ms) -{ - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); -} - -void AppManagerImplementation::Dispatch(EventNames event, const JsonObject params) -{ - switch(event) - { - case APP_EVENT_LIFECYCLE_STATE_CHANGED: - { - string appId = ""; - string appInstanceId = ""; - AppLifecycleState newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - AppLifecycleState oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - AppErrorReason errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - - if (!(params.HasLabel("appId") && !(appId = params["appId"].String()).empty())) - { - LOGERR("appId not present or empty"); - } - else if (!params.HasLabel("newState")) - { - LOGERR("newState not present"); - } - else if (!params.HasLabel("oldState")) - { - LOGERR("oldState not present"); - } - else if (!params.HasLabel("errorReason")) - { - LOGERR("errorReason not present"); - } - else - { - appInstanceId = params.HasLabel("appInstanceId") ? params["appInstanceId"].String() : ""; - newState = static_cast(params["newState"].Number()); - oldState = static_cast(params["oldState"].Number()); - errorReason = static_cast(params["errorReason"].Number()); - mAdminLock.Lock(); - for (auto& notification : mAppManagerNotification) - { - notification->OnAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - } - mAdminLock.Unlock(); - } - break; - } - case APP_EVENT_INSTALLATION_STATUS: - { - string appId = ""; - string version = ""; - string installStatus = ""; - /* Check if 'packageId' exists and is not empty */ - appId = params.HasLabel("packageId") ? params["packageId"].String() : ""; - if (appId.empty()) - { - LOGERR("appId is missing or empty"); - } - else - { - installStatus = params.HasLabel("state") ? params["state"].String() : ""; - mAdminLock.Lock(); - for (auto& notification : mAppManagerNotification) - { - if (installStatus == "INSTALLED") - { - version = params.HasLabel("version") ? params["version"].String() : ""; - if (version.empty()) - { - LOGERR("version is empty for installed app"); - } - LOGINFO("OnAppInstalled appId %s version %s", appId.c_str(), version.c_str()); - notification->OnAppInstalled(appId, version); - } - else if (installStatus == "UNINSTALLED") - { - LOGINFO("OnAppUninstalled appId %s", appId.c_str()); - notification->OnAppUninstalled(appId); - } - else - { - LOGWARN("install status '%s' for appId %s", installStatus.c_str(), appId.c_str()); - } - } - mAdminLock.Unlock(); - } - break; - } - case APP_EVENT_LAUNCH_REQUEST: - { - string appId = ""; - string intent = ""; - string source = ""; - - appId = params.HasLabel("appId") ? params["appId"].String() : ""; - if (appId.empty()) - { - LOGERR("appId is missing or empty"); - } - else - { - intent = params.HasLabel("intent") ? params["intent"].String() : ""; - if (intent.empty()) - { - LOGERR("intent is empty for Launch app"); - } - source = params.HasLabel("source") ? params["source"].String() : ""; - if (source.empty()) - { - LOGERR("source is empty for Launch app"); - } - mAdminLock.Lock(); - for (auto& notification : mAppManagerNotification) - { - notification->OnAppLaunchRequest(appId, intent, source); - } - mAdminLock.Unlock(); - } - break; - } - case APP_EVENT_UNLOADED: - { - string appId = ""; - string appInstanceId = ""; - - appId = params.HasLabel("appId") ? params["appId"].String() : ""; - if (appId.empty()) - { - LOGERR("appId is missing or empty"); - } - else - { - appInstanceId = params.HasLabel("appInstanceId") ? params["appInstanceId"].String() : ""; - if (appInstanceId.empty()) - { - LOGERR("appInstanceId is empty for Unloaded app"); - } - - mAdminLock.Lock(); - Core::hresult unlockStatus = packageUnLock(appId); - LOGINFO("package unlock triggered while sending unloaded event for appId %s status %d", appId.c_str(), unlockStatus); - for (auto& notification : mAppManagerNotification) - { - notification->OnAppUnloaded(appId, appInstanceId); - } - mAdminLock.Unlock(); - removeAppInfoByAppId(appId); - } - break; - } - default: - LOGERR("Unknown event: %d", static_cast(event)); - break; - } - -} - -/* - * @brief Notify client on App state change. - * @Params[in] : const string& appId, const string& appInstanceId, const AppLifecycleState newState, const AppLifecycleState oldState, const AppErrorReason errorReason - * @Params[out] : None - * @return : void - */ -void AppManagerImplementation::handleOnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, - const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) -{ - JsonObject eventDetails; - - eventDetails["appId"] = appId; - eventDetails["appInstanceId"] = appInstanceId; - eventDetails["newState"] = static_cast(newState); - eventDetails["oldState"] = static_cast(oldState); - eventDetails["errorReason"] = static_cast(errorReason); - - LOGINFO("Notify App Lifecycle state change for appId %s: appInstanceId %s oldState=%d, newState=%d", - appId.c_str(), (appInstanceId.empty()?" ":appInstanceId.c_str()), static_cast(oldState), static_cast(newState)); - - dispatchEvent(APP_EVENT_LIFECYCLE_STATE_CHANGED, eventDetails); -} - -/* - * @brief Notify client on App Unloaded - * @Params[in] : const string& appId, const string& appInstanceId - * @Params[out] : None - * @return : void - */ -void AppManagerImplementation::handleOnAppUnloaded(const string& appId, const string& appInstanceId) -{ - JsonObject eventDetails; - - if(appId.empty()) - { - LOGERR("appId not present or empty"); - } - else - { - eventDetails["appId"] = appId; - eventDetails["appInstanceId"] = appInstanceId; - - LOGINFO("Notify App Lifecycle state change for appId %s: appInstanceId %s", - appId.c_str(), appInstanceId.c_str()); - - dispatchEvent(APP_EVENT_UNLOADED, eventDetails); - } -} - -/* - * @brief Notify client on App LaunchRequest - * @Params[in] : const string& appId, const string& intent, const string &source - * @Params[out] : None - * @return : void - */ -void AppManagerImplementation::handleOnAppLaunchRequest(const string& appId, const string& intent, const string& source) -{ - JsonObject eventDetails; - - if(appId.empty()) - { - LOGERR("appId not present or empty"); - } - else - { - eventDetails["appId"] = appId; - eventDetails["intent"] = intent; - eventDetails["source"] = source; - - LOGINFO("Notify onAppLaunchRequest for appId %s: intent=%s", - appId.c_str(),intent.c_str()); - - dispatchEvent(APP_EVENT_LAUNCH_REQUEST, eventDetails); - } -} - -uint32_t AppManagerImplementation::Configure(PluginHost::IShell* service) -{ - uint32_t result = Core::ERROR_GENERAL; - - if (service != nullptr) - { - mCurrentservice = service; - mCurrentservice->AddRef(); - - if (nullptr == (mLifecycleInterfaceConnector = new LifecycleInterfaceConnector(mCurrentservice))) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - else if (Core::ERROR_NONE != mLifecycleInterfaceConnector->createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - else - { - LOGINFO("created LifecycleManagerRemoteObject"); - } - - if (Core::ERROR_NONE != createPersistentStoreRemoteStoreObject()) - { - LOGERR("Failed to create createPersistentStoreRemoteStoreObject"); - } - else - { - LOGINFO("created createPersistentStoreRemoteStoreObject"); - } - - if (Core::ERROR_NONE != createPackageManagerObject()) - { - LOGERR("Failed to create createPackageManagerObject"); - } - else - { - LOGINFO("created createPackageManagerObject"); - } - - if (Core::ERROR_NONE != createStorageManagerRemoteObject()) - { - LOGERR("Failed to create createStorageManagerRemoteObject"); - } - else - { - LOGINFO("created createStorageManagerRemoteObject"); - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting::getInstance().initialize(service); -#endif - sRunning = true; - /* Create the worker thread */ - try - { - mAppManagerWorkerThread = std::thread(&AppManagerImplementation::AppManagerWorkerThread, AppManagerImplementation::getInstance()); - LOGINFO("App Manager Worker thread created"); - result = Core::ERROR_NONE; - } - catch (const std::system_error& e) - { - LOGERR("Failed to create App Manager worker thread: %s", e.what()); - } - } - else - { - LOGERR("service is null \n"); - } - - return result; -} - -Core::hresult AppManagerImplementation::createPersistentStoreRemoteStoreObject() -{ - Core::hresult status = Core::ERROR_GENERAL; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null \n"); - } - else if (nullptr == (mPersistentStoreRemoteStoreObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.PersistentStore"))) - { - LOGERR("mPersistentStoreRemoteStoreObject is null \n"); - } - else - { - LOGINFO("created PersistentStore Object\n"); - status = Core::ERROR_NONE; - } - return status; -} - -void AppManagerImplementation::releasePersistentStoreRemoteStoreObject() -{ - ASSERT(nullptr != mPersistentStoreRemoteStoreObject); - if(mPersistentStoreRemoteStoreObject) - { - mPersistentStoreRemoteStoreObject->Release(); - mPersistentStoreRemoteStoreObject = nullptr; - } -} - -Core::hresult AppManagerImplementation::createPackageManagerObject() -{ - Core::hresult status = Core::ERROR_GENERAL; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null \n"); - } - else if (nullptr == (mPackageManagerHandlerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.PackageManagerRDKEMS"))) - { - LOGERR("mPackageManagerHandlerObject is null \n"); - } - else if (nullptr == (mPackageManagerInstallerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.PackageManagerRDKEMS"))) - { - LOGERR("mPackageManagerInstallerObject is null \n"); - } - else - { - LOGINFO("created PackageManager Object\n"); - mPackageManagerInstallerObject->AddRef(); - mPackageManagerInstallerObject->Register(&mPackageManagerNotification); - status = Core::ERROR_NONE; - } - return status; -} - -void AppManagerImplementation::releasePackageManagerObject() -{ - ASSERT(nullptr != mPackageManagerHandlerObject); - if(mPackageManagerHandlerObject) - { - mPackageManagerHandlerObject->Release(); - mPackageManagerHandlerObject = nullptr; - } - ASSERT(nullptr != mPackageManagerInstallerObject); - if(mPackageManagerInstallerObject) - { - mPackageManagerInstallerObject->Unregister(&mPackageManagerNotification); - mPackageManagerInstallerObject->Release(); - mPackageManagerInstallerObject = nullptr; - } -} - -Core::hresult AppManagerImplementation::createStorageManagerRemoteObject() -{ - #define MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES 2 - - Core::hresult status = Core::ERROR_GENERAL; - uint8_t retryCount = 0; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null"); - } - else - { - do - { - mStorageManagerRemoteObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.StorageManager"); - - if (nullptr == mStorageManagerRemoteObject) - { - LOGERR("storageManagerRemoteObject is null (Attempt %d)", retryCount + 1); - retryCount++; - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - else - { - LOGINFO("Successfully created Storage Manager Object"); - status = Core::ERROR_NONE; - break; - } - } while (retryCount < MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES); - - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to create Storage Manager Object after %d attempts", MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES); - } - } - return status; -} - -void AppManagerImplementation::releaseStorageManagerRemoteObject() -{ - ASSERT(nullptr != mStorageManagerRemoteObject); - if(mStorageManagerRemoteObject) - { - mStorageManagerRemoteObject->Release(); - mStorageManagerRemoteObject = nullptr; - } -} - -bool AppManagerImplementation::createOrUpdatePackageInfoByAppId(const string& appId, PackageInfo &packageData) -{ - bool result = false; - if( packageData.version.empty() || packageData.unpackedPath.empty()) - { - LOGWARN("AppId[%s] unpacked path is empty! or version is empty ", appId.c_str()); - } - else - { - /* Check if the appId exists in the map */ - auto it = mAppInfo.find(appId); - if (it != mAppInfo.end()) - { - /* Update existing entry (PackageInfo inside LoadedAppInfo) */ - it->second.packageInfo.version = packageData.version; - it->second.packageInfo.lockId = packageData.lockId; - it->second.packageInfo.unpackedPath = packageData.unpackedPath; - it->second.packageInfo.configMetadata = packageData.configMetadata; - it->second.packageInfo.appMetadata = packageData.appMetadata; - - LOGINFO("Existing package entry updated for appId: %s " \ - "version: %s lockId: %d unpackedPath: %s appMetadata: %s", - appId.c_str(), it->second.packageInfo.version.c_str(), - it->second.packageInfo.lockId, it->second.packageInfo.unpackedPath.c_str(), - it->second.packageInfo.appMetadata.c_str()); - } - else - { - /* Create new entry (PackageInfo inside LoadedAppInfo) */ - mAppInfo[appId].packageInfo.version = packageData.version; - mAppInfo[appId].packageInfo.lockId = packageData.lockId; - mAppInfo[appId].packageInfo.unpackedPath = packageData.unpackedPath; - mAppInfo[appId].packageInfo.configMetadata = packageData.configMetadata; - mAppInfo[appId].packageInfo.appMetadata = packageData.appMetadata; - - LOGINFO("Created new package entry for appId: %s " \ - "version: %s lockId: %d unpackedPath: %s appMetadata: %s", - appId.c_str(), mAppInfo[appId].packageInfo.version.c_str(), - mAppInfo[appId].packageInfo.lockId, mAppInfo[appId].packageInfo.unpackedPath.c_str(), - mAppInfo[appId].packageInfo.appMetadata.c_str()); - } - result = true; - } - - return result; -} - -bool AppManagerImplementation::removeAppInfoByAppId(const string &appId) -{ - bool result = false; - - /* Check if appId StorageInfo is found, erase it */ - auto it = mAppInfo.find(appId); - if (it != mAppInfo.end()) - { - LOGINFO("Existing package entry updated for appId: %s " \ - "version: %s lockId: %d unpackedPath: %s appMetadata: %s", - appId.c_str(), it->second.packageInfo.version.c_str(), it->second.packageInfo.lockId, it->second.packageInfo.unpackedPath.c_str(), it->second.packageInfo.appMetadata.c_str()); - mAppInfo.erase(appId); - result = true; - } - else - { - LOGWARN("AppId[%s] PackageInfo not found", appId.c_str()); - } - return result; -} -Core::hresult AppManagerImplementation::packageLock(const string& appId, PackageInfo &packageData, Exchange::IPackageHandler::LockReason lockReason) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool result = false; - bool installed = false; - bool loaded = false; - std::vector packageList; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->isAppLoaded(appId, loaded); - } - - /* Check if appId exists in the mAppInfo map */ - auto it = mAppInfo.find(appId); - - if ((status == Core::ERROR_NONE) && - (!loaded || - it == mAppInfo.end() || - (it->second.appNewState != Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED && it->second.appNewState != Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED && it->second.appNewState != Exchange::IAppManager::AppLifecycleState::APP_STATE_HIBERNATED))) - { - /* Fetch list of App packages */ - status = fetchAppPackageList(packageList); - - if (status == Core::ERROR_NONE) - { - /* Check if appId is installed */ - checkIsInstalled(appId, installed, packageList); - - if (installed) - { - /* Check if the packageId matches the provided appId */ - for (const auto& package : packageList) - { - if (!package.packageId.empty() && package.packageId == appId && package.state == Exchange::IPackageInstaller::InstallState::INSTALLED) - { - packageData.version = std::string(package.version); - break; - } - } - LOGINFO("packageData call lock %s", packageData.version.c_str()); - /* Ensure package version is valid before proceeding with the Lock */ - if ((nullptr != mPackageManagerHandlerObject) && !packageData.version.empty()) - { - Exchange::IPackageHandler::ILockIterator *appMetadata = nullptr; - status = mPackageManagerHandlerObject->Lock(appId, packageData.version, lockReason, packageData.lockId, packageData.unpackedPath, packageData.configMetadata, appMetadata); - if (status == Core::ERROR_NONE) - { - LOGINFO("Fetching package entry updated for appId: %s version: %s lockId: %d unpackedPath: %s appMetadata: %s", - appId.c_str(), packageData.version.c_str(), packageData.lockId, packageData.unpackedPath.c_str(), packageData.appMetadata.c_str()); - result = createOrUpdatePackageInfoByAppId(appId, packageData); - - /* If package info update failed, set error status */ - if (!result) - { - LOGERR("Failed to createOrUpdate the PackageInfo"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_PACKAGE_INVALID); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("Failed to PackageManager Lock %s", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_PACKAGE_LOCK); -#endif - packageData.version.clear(); /* Clear version on failure */ - } - } - else - { - LOGERR("PackageManager handler is %s", (nullptr != mPackageManagerHandlerObject) ? "valid, but package version is empty" : "null"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - CurrentActionError errorCode = (packageData.version.empty()?AppManagerImplementation::ERROR_PACKAGE_INVALID:AppManagerImplementation::ERROR_INTERNAL); - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, errorCode); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("isInstalled Failed for appId: %s", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_PACKAGE_NOT_INSTALLED); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("Failed to Get the list of Packages"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_PACKAGE_LIST_FETCH); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("Skipping packageLock for appId %s: ", appId.c_str()); - } - - return status; -} - -Core::hresult AppManagerImplementation::packageUnLock(const string& appId) -{ - Core::hresult status = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - - auto it = mAppInfo.find(appId); - if (it != mAppInfo.end()) - { - if (nullptr != mPackageManagerHandlerObject) - { - status = mPackageManagerHandlerObject->Unlock(appId, it->second.packageInfo.version); - - if(Core::ERROR_NONE != status) - { - LOGERR("Failed to PackageManager Unlock "); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_PACKAGE_UNLOCK); -#endif - } - } - else - { - LOGERR("PackageManager handler is %s",((nullptr != mPackageManagerHandlerObject) ? "valid": "null")); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - } - else - { - LOGERR("AppId not found in map to get the version"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INVALID_PARAMS); -#endif - } - return status; -} -/* - * @brief Launch App requested by client. - * @Params[in] : const string& appId , const string& intent, const string& launchArgs - * @Params[out] : None - * @return : Core::hresult - */ -Core::hresult AppManagerImplementation::LaunchApp(const string& appId , const string& intent , const string& launchArgs) -{ - Core::hresult status = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); - time_t requestTime = appManagerTelemetryReporting.getCurrentTimestamp(); -#endif - LOGINFO(" LaunchApp enter with appId %s", appId.c_str()); - - mAdminLock.Lock(); - if (appId.empty()) - { - LOGERR("application Id is empty"); - status = Core::ERROR_INVALID_PARAMETER; - } - else if (nullptr != mLifecycleInterfaceConnector) - { - std::shared_ptr request = std::make_shared(); - - if (request != nullptr) - { - LOGINFO("LaunchApp enter with appId %s", appId.c_str()); - request->mRequestAction = APP_ACTION_LAUNCH; - request->mRequestParam = std::make_shared(AppLaunchRequestParam{appId, launchArgs, intent}); - if (request->mRequestParam != nullptr) - { - mAppManagerLock.lock(); - mAppRequestList.push_back(request); - mAppManagerLock.unlock(); - mAppRequestListCV.notify_one(); - status = Core::ERROR_NONE; - } - else - { - LOGERR("Failed to perform operation due to no memory"); - } - } - else - { - LOGERR("Failed to perform operation due to no memory"); - } - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if(status == Core::ERROR_NONE) - { - updateCurrentActionTime(appId, requestTime, AppManagerImplementation::APP_ACTION_LAUNCH); - appManagerTelemetryReporting.reportTelemetryData(appId, AppManagerImplementation::APP_ACTION_LAUNCH); - } -#endif - mAdminLock.Unlock(); - - LOGINFO(" LaunchApp returns with status %d", status); - return status; -} - -/* - * This function handles the process of closing an app by moving it from the ACTIVE state to the RUNNING state. - * The state change is performed by the Lifecycle Manager. - * If the app's state is not ACTIVE, the function does nothing. - * - * Input: - * - const string& appId: The ID of the application to be closed. - * - * Output: - * - Returns a Core::hresult status code: - * - Core::ERROR_NONE on success. - * - Core::ERROR_GENERAL on error. - */ -Core::hresult AppManagerImplementation::CloseApp(const string& appId) -{ - Core::hresult status = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); - time_t requestTime = appManagerTelemetryReporting.getCurrentTimestamp(); -#endif - LOGINFO("CloseApp Entered with appId %s", appId.c_str()); - - if (!appId.empty()) - { - mAdminLock.Lock(); - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->closeApp(appId); - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if(status == Core::ERROR_NONE) - { - updateCurrentActionTime(appId, requestTime, AppManagerImplementation::APP_ACTION_CLOSE); - appManagerTelemetryReporting.reportTelemetryData(appId, AppManagerImplementation::APP_ACTION_CLOSE); - } -#endif - mAdminLock.Unlock(); - } - else - { - LOGERR("appId is empty"); - } - return status; -} - -/* - * This function Starts terminating a running app. Lifecycle Manager will move the state into - * TERMINATE_REQUESTED - *.This will trigger a clean shutdown - * - * Input: - * - const string& appId: The ID of the application to be closed. - * - * Output: - * - Returns a Core::hresult status code: - * - Core::ERROR_NONE on success. - * - Core::ERROR_GENERAL on error. - */ -Core::hresult AppManagerImplementation::TerminateApp(const string& appId ) -{ - Core::hresult status = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); - time_t requestTime = appManagerTelemetryReporting.getCurrentTimestamp(); -#endif - LOGINFO(" TerminateApp Entered with appId %s", appId.c_str()); - - if (!appId.empty()) - { - mAdminLock.Lock(); - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->terminateApp(appId); - if(status == Core::ERROR_NONE) - { - status = packageUnLock(appId); - } - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if(status == Core::ERROR_NONE) - { - updateCurrentActionTime(appId, requestTime, AppManagerImplementation::APP_ACTION_TERMINATE); - appManagerTelemetryReporting.reportTelemetryData(appId, AppManagerImplementation::APP_ACTION_TERMINATE); - } -#endif - mAdminLock.Unlock(); - } - else - { - LOGERR("appId is empty"); - } - return status; -} - -Core::hresult AppManagerImplementation::KillApp(const string& appId) -{ - Core::hresult status = Core::ERROR_NONE; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); - time_t requestTime = appManagerTelemetryReporting.getCurrentTimestamp(); -#endif - LOGINFO("KillApp entered appId: '%s'", appId.c_str()); - - mAdminLock.Lock(); - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->killApp(appId); - if(status == Core::ERROR_NONE) - { - status = packageUnLock(appId); - } - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if(status == Core::ERROR_NONE) - { - updateCurrentActionTime(appId, requestTime, AppManagerImplementation::APP_ACTION_KILL); - appManagerTelemetryReporting.reportTelemetryData(appId, AppManagerImplementation::APP_ACTION_KILL); - } -#endif - mAdminLock.Unlock(); - - LOGINFO("KillApp exited"); - return status; -} - -Core::hresult AppManagerImplementation::GetLoadedApps(Exchange::IAppManager::ILoadedAppInfoIterator*& appData) -{ - Core::hresult status = Core::ERROR_GENERAL; - LOGINFO("GetLoadedApps Entered"); - mAdminLock.Lock(); - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->getLoadedApps(appData); - } - mAdminLock.Unlock(); - - LOGINFO(" GetLoadedApps returns with status %d", status); - return status; -} - -Core::hresult AppManagerImplementation::SendIntent(const string& appId , const string& intent) -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("SendIntent entered with appId '%s' and intent '%s'", appId.c_str(), intent.c_str()); - - mAdminLock.Lock(); - if (nullptr != mLifecycleInterfaceConnector) - { - status = mLifecycleInterfaceConnector->sendIntent(appId, intent); - } - mAdminLock.Unlock(); - - LOGINFO("SendIntent exited"); - return status; -} - -/*** - * @brief Preloads an Application. - * Preloads an Application and app will be in the RUNNING state (hidden). - * - * @param[in] appId : App identifier for the application - * @param[in] launchArgs(optional) : Additional parameters passed to the application - * @param[out] error : if success = false it holds the appropriate error reason - * - * @return : Core:: - */ -Core::hresult AppManagerImplementation::PreloadApp(const string& appId , const string& launchArgs ,string& error) -{ - Core::hresult status = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting = AppManagerTelemetryReporting::getInstance(); - time_t requestTime = appManagerTelemetryReporting.getCurrentTimestamp(); -#endif - LOGINFO(" PreloadApp enter with appId %s", appId.c_str()); - - mAdminLock.Lock(); - if (appId.empty()) - { - LOGERR("application Id is empty"); - error = "application Id is empty"; - status = Core::ERROR_INVALID_PARAMETER; - } - else if (nullptr != mLifecycleInterfaceConnector) - { - std::shared_ptr request = std::make_shared(); - - if (request != nullptr) - { - LOGINFO(" PreloadApp enter with appId %s", appId.c_str()); - request->mRequestAction = APP_ACTION_PRELOAD; - request->mRequestParam = std::make_shared(AppLaunchRequestParam{appId, launchArgs}); - if (request->mRequestParam != nullptr) - { - mAppManagerLock.lock(); - mAppRequestList.push_back(request); - mAppManagerLock.unlock(); - mAppRequestListCV.notify_one(); - status = Core::ERROR_NONE; - } - else - { - LOGERR("Failed to perform operation due to no memory"); - error = "Failed to perform operation due to no memory"; - } - } - else - { - LOGERR("Failed to perform operation due to no memory"); - error = "Failed to perform operation due to no memory"; - } - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if(status == Core::ERROR_NONE) - { - updateCurrentActionTime(appId, requestTime, AppManagerImplementation::APP_ACTION_PRELOAD); - appManagerTelemetryReporting.reportTelemetryData(appId, AppManagerImplementation::APP_ACTION_PRELOAD); - } -#endif - mAdminLock.Unlock(); - - LOGINFO(" PreloadApp returns with status %d", status); - return status; -} - -/*** - * @brief Gets a property for a given app. - * Gets a property for a given app based on the appId and key. - * - * @param[in] appId : App identifier for the application - * @param[in] key : the name of the property to get - * @param[out] value : value of the key queried, this can be a boolean, number, string or object type - * - * @return : Core:: - */ -Core::hresult AppManagerImplementation::GetAppProperty(const string& appId , const string& key , string& value ) -{ - LOGINFO("GetAppProperty Entered"); - Core::hresult status = Core::ERROR_GENERAL; - uint32_t ttl = 0; - if(appId.empty()) - { - LOGERR("Empty appId"); - } - else if(key.empty()) - { - LOGERR("Empty Key"); - } - else - { - mAdminLock.Lock(); - /* Checking if mPersistentStoreRemoteStoreObject is not valid then create the object, not required to destroy this object as it is handled in Destructor */ - if (nullptr == mPersistentStoreRemoteStoreObject) - { - LOGINFO("Create PersistentStore Remote store object"); - if (Core::ERROR_NONE != createPersistentStoreRemoteStoreObject()) - { - LOGERR("Failed to create createPersistentStoreRemoteStoreObject"); - } - } - ASSERT (nullptr != mPersistentStoreRemoteStoreObject); - if (nullptr != mPersistentStoreRemoteStoreObject) - { - status = mPersistentStoreRemoteStoreObject->GetValue(Exchange::IStore2::ScopeType::DEVICE, appId, key, value, ttl); - LOGINFO("Key[%s] value[%s] status[%d]", key.c_str(), value.c_str(), status); - if (Core::ERROR_NONE != status) - { - LOGERR("GetValue Failed"); - } - } - else - { - LOGERR("PersistentStore object is not valid"); - } - mAdminLock.Unlock(); - } - LOGINFO("GetAppProperty Exited"); - - return status; -} - -/*** - * @brief Sets a property for a given app. - * Sets a property for a given app based with given namespace, key and Value to persistentStore. - * - * @param[in] appId : App identifier for the application - * @param[in] key : the name of the property to get - * @param[in] value : the property value(json string format) to set, this can be a boolean, number, string or object type - * - * @return : Core:: - */ -Core::hresult AppManagerImplementation::SetAppProperty(const string& appId, const string& key, const string& value) -{ - Core::hresult status = Core::ERROR_GENERAL; - - if (appId.empty()) - { - LOGERR("appId is empty"); - } - else if (key.empty()) - { - LOGERR("key is empty"); - } - else - { - mAdminLock.Lock(); - - /* Checking if mPersistentStoreRemoteStoreObject is not valid then create the object */ - if (nullptr == mPersistentStoreRemoteStoreObject) - { - LOGINFO("Create PersistentStore Remote store object"); - if (Core::ERROR_NONE != createPersistentStoreRemoteStoreObject()) - { - LOGERR("Failed to create createPersistentStoreRemoteStoreObject"); - } - } - - ASSERT (nullptr != mPersistentStoreRemoteStoreObject); - if (nullptr != mPersistentStoreRemoteStoreObject) - { - status = mPersistentStoreRemoteStoreObject->SetValue(Exchange::IStore2::ScopeType::DEVICE, appId, key, value, 0); - } - else - { - LOGERR("PersistentStore object is not valid"); - } - - mAdminLock.Unlock(); - } - return status; -} - -Core::hresult AppManagerImplementation::fetchAppPackageList(std::vector& packageList) -{ - Core::hresult status = Core::ERROR_GENERAL; - packageList.clear(); - if (nullptr == mPackageManagerInstallerObject) - { - LOGINFO("Create PackageManager Remote store object"); - if (Core::ERROR_NONE != createPackageManagerObject()) - { - LOGERR("Failed to create PackageManagerObject"); - } - } - ASSERT (nullptr != mPackageManagerInstallerObject); - if (mPackageManagerInstallerObject != nullptr) - { - Exchange::IPackageInstaller::IPackageIterator* packages = nullptr; - - if (mPackageManagerInstallerObject->ListPackages(packages) != Core::ERROR_NONE || packages == nullptr) - { - LOGERR("ListPackage is returning Error or Packages is nullptr"); - goto End; - } - - WPEFramework::Exchange::IPackageInstaller::Package package; - while (packages->Next(package)) { - packageList.push_back(package); - } - status = Core::ERROR_NONE; - packages->Release(); - } - else - { - LOGERR("mPackageManagerInstallerObject is null "); - } -End: - return status; -} - -std::string AppManagerImplementation::getInstallAppType(ApplicationType type) -{ - switch (type) - { - case ApplicationType::APPLICATION_TYPE_INTERACTIVE : return "INTERACTIVE_APP"; - case ApplicationType::APPLICATION_TYPE_SYSTEM : return "SYSTEM_APP"; - default: return ""; - } -} - -Core::hresult AppManagerImplementation::GetInstalledApps(std::string& apps) -{ - Core::hresult status = Core::ERROR_GENERAL; - apps.clear(); - std::vector packageList; - JsonArray installedAppsArray; - char timeData[TIME_DATA_SIZE]; - - mAdminLock.Lock(); - - status = fetchAppPackageList(packageList); - if (status == Core::ERROR_NONE) - { - for (const auto& pkg : packageList) - { - /* Proceed only if the package is in the INSTALLED state */ - if(pkg.state == Exchange::IPackageInstaller::InstallState::INSTALLED) - { - JsonObject package; - package["appId"] = pkg.packageId; - package["versionString"] = pkg.version; - package["type"] = getInstallAppType(APPLICATION_TYPE_INTERACTIVE); - auto it = mAppInfo.find(pkg.packageId); - if (it != mAppInfo.end()) - { - const auto& timestamp = it->second.lastActiveStateChangeTime; - - if (strftime(timeData, sizeof(timeData), "%D %T", gmtime(×tamp.tv_sec))) - { - std::ostringstream lastActiveTime; - lastActiveTime << timeData << "." << std::setw(9) << std::setfill('0') << timestamp.tv_nsec; - package["lastActiveTime"] = lastActiveTime.str(); - } - else - { - package["lastActiveTime"] = ""; - } - package["lastActiveIndex"]=it->second.lastActiveIndex; - } - else - { - package["lastActiveTime"] =""; - package["lastActiveIndex"]=""; - } - installedAppsArray.Add(package); - } - } - installedAppsArray.ToString(apps); - LOGINFO("getInstalledApps: %s", apps.c_str()); - } - - mAdminLock.Unlock(); - - return status; -} - -/* Method to check if the app is installed */ -void AppManagerImplementation::checkIsInstalled(const std::string& appId, bool& installed, const std::vector& packageList) -{ - installed = false; - - for (const auto& package : packageList) - { - /* Check if the package matches the appId and is in the INSTALLED state */ - if ((!package.packageId.empty()) && (package.packageId == appId) && (package.state == Exchange::IPackageInstaller::InstallState::INSTALLED)) - { - LOGINFO("%s is installed ",appId.c_str()); - installed = true; - break; - } - } - return; -} - -Core::hresult AppManagerImplementation::IsInstalled(const std::string& appId, bool& installed) -{ - Core::hresult status = Core::ERROR_GENERAL; - installed = false; - - mAdminLock.Lock(); - if(appId.empty()) - { - LOGERR("appId not present or empty"); - } - else - { - std::vector packageList; - status = fetchAppPackageList(packageList); - if (status == Core::ERROR_NONE) - { - checkIsInstalled(appId, installed, packageList); - if(installed) - { - LOGINFO("%s is installed ",appId.c_str()); - } - else - { - LOGINFO("%s is not installed ",appId.c_str()); - } - } - } - mAdminLock.Unlock(); - return status; -} - -Core::hresult AppManagerImplementation::StartSystemApp(const string& appId) -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("StartSystemApp Entered"); - - return status; -} - -Core::hresult AppManagerImplementation::StopSystemApp(const string& appId) -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("StopSystemApp Entered"); - - return status; -} - -Core::hresult AppManagerImplementation::ClearAppData(const string& appId) -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("ClearAppData Entered"); - - if (appId.empty()) - { - LOGERR("appId is empty"); - status = Core::ERROR_GENERAL; - return status; - } - - mAdminLock.Lock(); //required?? - if (nullptr != mStorageManagerRemoteObject) - { - std::string errorReason; - status = mStorageManagerRemoteObject->Clear(appId,errorReason); - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to clear app data for appId: %s errorReason : %s", appId.c_str(), errorReason.c_str()); - } - } - else - { - LOGERR("StorageManager Remote Object is null"); - status = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - - return status; -} - -Core::hresult AppManagerImplementation::ClearAllAppData() -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("ClearAllAppData Entered"); - - mAdminLock.Lock(); //required?? - if (nullptr != mStorageManagerRemoteObject) - { - std::string errorReason; - std::string exemptedAppIds = ""; - status = mStorageManagerRemoteObject->ClearAll(exemptedAppIds,errorReason); - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to clear all app data errorReason : %s", errorReason.c_str()); - } - } - else - { - LOGERR("StorageManager Remote Object is null"); - status = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - - return status; -} - -Core::hresult AppManagerImplementation::GetAppMetadata(const string& appId, const string& metaData, string& result) -{ - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("GetAppMetadata Entered"); - - return status; -} - -Core::hresult AppManagerImplementation::GetMaxRunningApps(int32_t& maxRunningApps) const -{ - LOGINFO("GetMaxRunningApps Entered"); - - maxRunningApps = -1; - - return Core::ERROR_NONE; -} - -Core::hresult AppManagerImplementation::GetMaxHibernatedApps(int32_t& maxHibernatedApps) const -{ - LOGINFO("GetMaxHibernatedApps Entered"); - - maxHibernatedApps = -1; - - return Core::ERROR_NONE; -} - -Core::hresult AppManagerImplementation::GetMaxHibernatedFlashUsage(int32_t& maxHibernatedFlashUsage) const -{ - LOGINFO("GetMaxHibernatedFlashUsage Entered"); - - maxHibernatedFlashUsage = -1; - - return Core::ERROR_NONE; -} - -Core::hresult AppManagerImplementation::GetMaxInactiveRamUsage(int32_t& maxInactiveRamUsage) const -{ - LOGINFO("GetMaxInactiveRamUsage Entered"); - - maxInactiveRamUsage = -1; - - return Core::ERROR_NONE; -} - -void AppManagerImplementation::OnAppInstallationStatus(const string& jsonresponse) -{ - LOGINFO("Received JSON response: %s", jsonresponse.c_str()); - - if (!jsonresponse.empty()) - { - JsonArray list; - if (list.FromString(jsonresponse)) - { - for (size_t i = 0; i < list.Length(); ++i) - { - JsonObject params = list[i].Object(); - dispatchEvent(APP_EVENT_INSTALLATION_STATUS, params); - } - } - else - { - LOGERR("Failed to parse JSON string\n"); - } - } - else - { - LOGERR("jsonresponse string is empty"); - } -} - -void AppManagerImplementation::getCustomValues(WPEFramework::Exchange::RuntimeConfig& runtimeConfig) -{ - FILE* fp = fopen("/tmp/aipath", "r"); - bool aipathchange = false; - std::string apppath, runtimepath, command; - if (fp != NULL) - { - aipathchange = true; - char* line = NULL; - size_t len = 0; - bool first = true, second = true, third = true; - while ((getline(&line, &len, fp)) != -1) - { - if (first) - { - apppath = line; - first = false; - } - else if (second) - { - runtimepath = line; - second = false; - } - else if (third) - { - command = line; - third = false; - } - } - fclose(fp); - } - apppath.pop_back(); - runtimepath.pop_back(); - command.pop_back(); - - if (aipathchange) - { - runtimeConfig.appPath = apppath; - runtimeConfig.runtimePath = runtimepath; - runtimeConfig.command = command; - runtimeConfig.appType = 1; - runtimeConfig.resourceManagerClientEnabled = true; - } -} - -void AppManagerImplementation::updateCurrentAction(const std::string& appId, CurrentAction action) -{ - auto it = mAppInfo.find(appId); - if(it != mAppInfo.end()) - { - it->second.currentAction = action; - LOGINFO("Updated currentAction for appId %s to %d", appId.c_str(), static_cast(action)); - } - else - { - LOGERR("App ID %s not found while updating currentAction", appId.c_str()); - } -} -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -void AppManagerImplementation::updateCurrentActionTime(const std::string& appId, time_t currentActionTime, CurrentAction currentAction) -{ - auto it = mAppInfo.find(appId); - if((it != mAppInfo.end()) && (currentAction == it->second.currentAction)) - { - it->second.currentActionTime = currentActionTime; - LOGINFO("Updated currentActionTime for appId %s", appId.c_str()); - } - else - { - LOGERR("Failed to updating currentActionTime for appId %s", appId.c_str()); - } -} -#endif - -bool AppManagerImplementation::checkInstallUninstallBlock(const std::string& appId) -{ - bool blocked = false; - int duplicateCount = 0; - - std::vector packageList; - Core::hresult status = fetchAppPackageList(packageList); - - if (status != Core::ERROR_NONE) { - LOGERR("Failed to fetch package list for appId: %s", appId.c_str()); - return false; - } - - for (const auto& package : packageList) { - if ((!package.packageId.empty()) && (package.packageId == appId)) { - duplicateCount++; - if (package.state == Exchange::IPackageInstaller::InstallState::INSTALLATION_BLOCKED || - package.state == Exchange::IPackageInstaller::InstallState::UNINSTALL_BLOCKED) { - blocked = true; - LOGINFO("checkInstallUninstallBlock: appId=%s,package_state=%d", appId.c_str(), static_cast(package.state)); - break; - } - } - } - LOGINFO("checkInstallUninstallBlock: appId=%s duplicateCount=%d blocked=%d", appId.c_str(), duplicateCount, blocked); - return blocked; -} -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/AppManager/AppManagerImplementation.h b/AppManager/AppManagerImplementation.h deleted file mode 100755 index 8af5208..0000000 --- a/AppManager/AppManagerImplementation.h +++ /dev/null @@ -1,282 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include -#include -#include "tracing/Logging.h" -#include -#include -#include -#include "LifecycleInterfaceConnector.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class AppManagerImplementation : public Exchange::IAppManager, public Exchange::IConfiguration { - - public: - AppManagerImplementation(); - ~AppManagerImplementation() override; - - static AppManagerImplementation* getInstance(); - AppManagerImplementation(const AppManagerImplementation&) = delete; - AppManagerImplementation& operator=(const AppManagerImplementation&) = delete; - - BEGIN_INTERFACE_MAP(AppManagerImplementation) - INTERFACE_ENTRY(Exchange::IAppManager) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - public: - typedef enum _ApplicationType - { - APPLICATION_TYPE_UNKNOWN = 0, - APPLICATION_TYPE_INTERACTIVE, - APPLICATION_TYPE_SYSTEM - } ApplicationType; - - typedef struct _PackageInfo - { - string version = ""; - uint32_t lockId = 0; - string unpackedPath = "" ; - WPEFramework::Exchange::RuntimeConfig configMetadata; - string appMetadata = ""; - ApplicationType type; - } PackageInfo; - - enum CurrentAction { - APP_ACTION_NONE, - APP_ACTION_LAUNCH, - APP_ACTION_PRELOAD, - APP_ACTION_SUSPEND, - APP_ACTION_RESUME, - APP_ACTION_CLOSE, - APP_ACTION_TERMINATE, - APP_ACTION_HIBERNATE, - APP_ACTION_KILL, - }; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - enum CurrentActionError{ - ERROR_NONE, - ERROR_INVALID_PARAMS, - ERROR_INTERNAL, - ERROR_PACKAGE_LOCK, - ERROR_PACKAGE_UNLOCK, - ERROR_PACKAGE_LIST_FETCH, - ERROR_PACKAGE_NOT_INSTALLED, - ERROR_PACKAGE_INVALID, - ERROR_SPAWN_APP, - ERROR_UNLOAD_APP, - ERROR_KILL_APP, - ERROR_SET_TARGET_APP_STATE - }; -#endif - - typedef struct _AppInfo - { - /* From LifecycleManager */ - string appInstanceId; - string activeSessionId; - /* From PackageManager */ - PackageInfo packageInfo; - /* App launch params*/ - Exchange::IAppManager::AppLifecycleState appNewState; - Exchange::ILifecycleManager::LifecycleState appLifecycleState; - timespec lastActiveStateChangeTime; - uint32_t lastActiveIndex; - string appIntent; - Exchange::IAppManager::AppLifecycleState targetAppState; - Exchange::IAppManager::AppLifecycleState appOldState; - /* Current Action*/ - CurrentAction currentAction = APP_ACTION_NONE; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - time_t currentActionTime; -#endif - } AppInfo; - - std::map mAppInfo; - - enum EventNames { - APP_EVENT_UNKNOWN = 0, - APP_EVENT_LIFECYCLE_STATE_CHANGED, - APP_EVENT_INSTALLATION_STATUS, - APP_EVENT_LAUNCH_REQUEST, - APP_EVENT_UNLOADED - }; - - struct AppLaunchRequestParam{ - string appId; - string launchArgs; - string intent; - }; - - struct AppManagerRequest{ - CurrentAction mRequestAction; - std::shared_ptr mRequestParam; - }; - - private: - class PackageManagerNotification : public Exchange::IPackageInstaller::INotification { - - public: - PackageManagerNotification(AppManagerImplementation& parent) : mParent(parent){} - ~PackageManagerNotification(){} - - void OnAppInstallationStatus(const string& jsonresponse) - { - LOGINFO("AppManagerImplementation on OnAppInstallationStatus"); - mParent.OnAppInstallationStatus(jsonresponse); - } - - BEGIN_INTERFACE_MAP(PackageManagerNotification) - INTERFACE_ENTRY(Exchange::IPackageInstaller::INotification) - END_INTERFACE_MAP - - private: - AppManagerImplementation& mParent; - }; - - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(AppManagerImplementation *appManagerImplementation, EventNames event, JsonObject ¶ms) - : mAppManagerImplementation(appManagerImplementation) - , _event(event) - , _params(params) { - if (mAppManagerImplementation != nullptr) { - mAppManagerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (mAppManagerImplementation != nullptr) { - mAppManagerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(AppManagerImplementation *appManagerImplementation, EventNames event, JsonObject params) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(appManagerImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(appManagerImplementation, event, params))); -#endif - } - - virtual void Dispatch() { - mAppManagerImplementation->Dispatch(_event, _params); - } - private: - AppManagerImplementation *mAppManagerImplementation; - const EventNames _event; - const JsonObject _params; - }; - - public: - Core::hresult Register(Exchange::IAppManager::INotification *notification) override ; - Core::hresult Unregister(Exchange::IAppManager::INotification *notification) override ; - Core::hresult LaunchApp(const string& appId , const string& intent , const string& launchArgs) override; - Core::hresult CloseApp(const string& appId) override; - Core::hresult TerminateApp(const string& appId) override; - Core::hresult KillApp(const string& appId) override; - Core::hresult GetLoadedApps(Exchange::IAppManager::ILoadedAppInfoIterator*& appData) override; - Core::hresult SendIntent(const string& appId , const string& intent) override; - Core::hresult PreloadApp(const string& appId , const string& launchArgs ,string& error) override; - Core::hresult GetAppProperty(const string& appId , const string& key , string& value) override; - Core::hresult SetAppProperty(const string& appId , const string& key ,const string& value) override; - Core::hresult GetInstalledApps(string& apps) override; - Core::hresult IsInstalled(const string& appId, bool& installed) override; - Core::hresult StartSystemApp(const string& appId) override; - Core::hresult StopSystemApp(const string& appId) override; - Core::hresult ClearAppData(const string& appId) override; - Core::hresult ClearAllAppData() override; - Core::hresult GetAppMetadata(const string& appId, const string& metaData, string& result) override; - Core::hresult GetMaxRunningApps(int32_t& maxRunningApps) const override; - Core::hresult GetMaxHibernatedApps(int32_t& maxHibernatedApps) const override; - Core::hresult GetMaxHibernatedFlashUsage(int32_t& maxHibernatedFlashUsage) const override; - Core::hresult GetMaxInactiveRamUsage(int32_t& maxInactiveRamUsage) const override; - void handleOnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, - const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason); - void handleOnAppUnloaded(const string& appId, const string& appInstanceId); - void handleOnAppLaunchRequest(const string& appId, const string& intent, const string& source); - std::string getInstallAppType(ApplicationType type); - - // IConfiguration methods - uint32_t Configure(PluginHost::IShell* service) override; - - private: /* private methods */ - Core::hresult createPersistentStoreRemoteStoreObject(); - void releasePersistentStoreRemoteStoreObject(); - Core::hresult createPackageManagerObject(); - void releasePackageManagerObject(); - void getCustomValues(WPEFramework::Exchange::RuntimeConfig& runtimeConfig); - Core::hresult createStorageManagerRemoteObject(); - void releaseStorageManagerRemoteObject(); - private: - mutable Core::CriticalSection mAdminLock; - std::list mAppManagerNotification; - LifecycleInterfaceConnector* mLifecycleInterfaceConnector; - Exchange::IStore2* mPersistentStoreRemoteStoreObject; - Exchange::IPackageHandler* mPackageManagerHandlerObject; - Exchange::IPackageInstaller* mPackageManagerInstallerObject; - Exchange::IStorageManager* mStorageManagerRemoteObject; - PluginHost::IShell* mCurrentservice; - Core::Sink mPackageManagerNotification; - std::thread mAppManagerWorkerThread; - std::mutex mAppManagerLock; - std::condition_variable mAppRequestListCV; - std::list> mAppRequestList; - Core::hresult fetchAppPackageList(std::vector& packageList); - void checkIsInstalled(const std::string& appId, bool& installed, const std::vector& packageList); - Core::hresult packageLock(const string& appId, PackageInfo &packageData, Exchange::IPackageHandler::LockReason lockReason); - Core::hresult packageUnLock(const string& appId); - bool createOrUpdatePackageInfoByAppId(const string& appId, PackageInfo &packageData); - bool removeAppInfoByAppId(const string &appId); - void OnAppInstallationStatus(const string& jsonresponse); - void AppManagerWorkerThread(void); - void dispatchEvent(EventNames, const JsonObject ¶ms); - void Dispatch(EventNames event, const JsonObject params); - friend class Job; - - public/*members*/: - static AppManagerImplementation* _instance; - - public: /* public methods */ - void updateCurrentAction(const std::string& appId, CurrentAction action); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - void updateCurrentActionTime(const std::string& appId, time_t currentActionTime, CurrentAction currentAction); -#endif - bool checkInstallUninstallBlock(const std::string& appId); - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/AppManager/AppManagerTelemetryReporting.cpp b/AppManager/AppManagerTelemetryReporting.cpp deleted file mode 100755 index 3a8b3c1..0000000 --- a/AppManager/AppManagerTelemetryReporting.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "AppManagerTelemetryReporting.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" - -namespace WPEFramework -{ -namespace Plugin -{ - AppManagerTelemetryReporting::AppManagerTelemetryReporting(): mTelemetryMetricsObject(nullptr), mCurrentservice(nullptr) - { - } - - AppManagerTelemetryReporting::~AppManagerTelemetryReporting() - { - } - - AppManagerTelemetryReporting& AppManagerTelemetryReporting::getInstance() - { - LOGINFO("Get AppManagerTelemetryReporting Instance"); - static AppManagerTelemetryReporting instance; - return instance; - } - - void AppManagerTelemetryReporting::initialize(PluginHost::IShell* service) - { - ASSERT(nullptr != service); - mAdminLock.Lock(); - mCurrentservice = service; - mAdminLock.Unlock(); - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - time_t AppManagerTelemetryReporting::getCurrentTimestamp() - { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((time_t)(ts.tv_sec * 1000) + ((time_t)ts.tv_nsec/1000000)); - } - - Core::hresult AppManagerTelemetryReporting::createTelemetryMetricsPluginObject() - { - Core::hresult status = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null \n"); - } - else if (nullptr == (mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"))) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - else - { - status = Core::ERROR_NONE; - LOGINFO("created TelemetryMetrics Object"); - } - mAdminLock.Unlock(); - return status; - } - - void AppManagerTelemetryReporting::reportTelemetryData(const std::string& appId, AppManagerImplementation::CurrentAction currentAction) - { - JsonObject jsonParam; - std::string telemetryMetrics = ""; - std::string markerName = ""; - time_t currentTime = getCurrentTimestamp(); - AppManagerImplementation*appManagerImplInstance = AppManagerImplementation::getInstance(); - - if(nullptr == mTelemetryMetricsObject) /*mTelemetryMetricsObject is null retry to create*/ - { - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - auto it = appManagerImplInstance->mAppInfo.find(appId); - if((it != appManagerImplInstance->mAppInfo.end()) && (currentAction == it->second.currentAction) && (nullptr != mTelemetryMetricsObject)) - { - LOGINFO("Received data for appId %s current action %d ",appId.c_str(), currentAction); - - switch(currentAction) - { - case AppManagerImplementation::APP_ACTION_LAUNCH: - case AppManagerImplementation::APP_ACTION_PRELOAD: - jsonParam["appManagerLaunchTime"] = (int)(currentTime - it->second.currentActionTime); - markerName = TELEMETRY_MARKER_LAUNCH_TIME; - break; - case AppManagerImplementation::APP_ACTION_CLOSE: - if ((Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED != it->second.targetAppState) && - (Exchange::IAppManager::AppLifecycleState::APP_STATE_HIBERNATED != it->second.targetAppState)) - { - jsonParam["appManagerCloseTime"] = (int)(currentTime - it->second.currentActionTime); - markerName = TELEMETRY_MARKER_CLOSE_TIME; - } - break; - case AppManagerImplementation::APP_ACTION_TERMINATE: - case AppManagerImplementation::APP_ACTION_KILL: - jsonParam["appManagerCloseTime"] = (int)(currentTime - it->second.currentActionTime); - markerName = TELEMETRY_MARKER_CLOSE_TIME; - break; - default: - LOGERR("currentAction is invalid"); - break; - } - - if(!markerName.empty()) - { - jsonParam.ToString(telemetryMetrics); - if(!telemetryMetrics.empty()) - { - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - } - } - } - else - { - LOGERR("Failed to report telemetry data as appId/currentAction or mTelemetryMetricsObject is not valid"); - } - } - - void AppManagerTelemetryReporting::reportTelemetryDataOnStateChange(const string& appId, const Exchange::ILifecycleManager::LifecycleState newState) - { - JsonObject jsonParam; - std::string telemetryMetrics = ""; - std::string markerName = ""; - time_t currentTime = getCurrentTimestamp(); - AppManagerImplementation*appManagerImplInstance = AppManagerImplementation::getInstance(); - - if(nullptr == mTelemetryMetricsObject) /*mTelemetryMetricsObject is null retry to create*/ - { - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - auto it = appManagerImplInstance->mAppInfo.find(appId); - if((it != appManagerImplInstance->mAppInfo.end()) && (nullptr != mTelemetryMetricsObject)) - { - switch(it->second.currentAction) - { - case AppManagerImplementation::APP_ACTION_LAUNCH: - if(Exchange::ILifecycleManager::LifecycleState::ACTIVE == newState) - { - jsonParam["totalLaunchTime"] = (int)(currentTime - it->second.currentActionTime); - jsonParam["launchType"] = ((AppManagerImplementation::APPLICATION_TYPE_INTERACTIVE == it->second.packageInfo.type)?"LAUNCH_INTERACTIVE":"START_SYSTEM"); - markerName = TELEMETRY_MARKER_LAUNCH_TIME; - } - break; - case AppManagerImplementation::APP_ACTION_PRELOAD: - if(Exchange::ILifecycleManager::LifecycleState::PAUSED == newState) - { - jsonParam["totalLaunchTime"] = (int)(currentTime - it->second.currentActionTime); - jsonParam["launchType"] = ((AppManagerImplementation::APPLICATION_TYPE_INTERACTIVE == it->second.packageInfo.type)?"PRELOAD_INTERACTIVE":"START_SYSTEM"); - markerName = TELEMETRY_MARKER_LAUNCH_TIME; - } - break; - case AppManagerImplementation::APP_ACTION_CLOSE: - case AppManagerImplementation::APP_ACTION_TERMINATE: - case AppManagerImplementation::APP_ACTION_KILL: - if(Exchange::ILifecycleManager::LifecycleState::UNLOADED == newState) - { - jsonParam["totalCloseTime"] = (int)(currentTime - it->second.currentActionTime); - jsonParam["closeType"] = ((AppManagerImplementation::APP_ACTION_CLOSE == it->second.currentAction)?"CLOSE":((AppManagerImplementation::APP_ACTION_TERMINATE == it->second.currentAction)?"TERMINATE":"KILL")); - markerName = TELEMETRY_MARKER_CLOSE_TIME; - } - break; - default: - LOGERR("currentAction is invalid"); - break; - } - - if(!markerName.empty()) - { - jsonParam["appId"] = appId; - jsonParam["appInstanceId"] = it->second.appInstanceId; - jsonParam["appVersion"] = it->second.packageInfo.version; - jsonParam.ToString(telemetryMetrics); - if(!telemetryMetrics.empty()) - { - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - mTelemetryMetricsObject->Publish(appId, markerName); - } - } - } - else - { - LOGERR("Failed to report telemetry data as appId/mTelemetryMetricsObject is not valid"); - } - } - - void AppManagerTelemetryReporting::reportTelemetryErrorData(const std::string& appId, AppManagerImplementation::CurrentAction currentAction, AppManagerImplementation::CurrentActionError errorCode) - { - JsonObject jsonParam; - std::string telemetryMetrics = ""; - std::string markerName = ""; - - LOGINFO("Received data for appId %s current action %d app errorCode %d",appId.c_str(), currentAction, errorCode); - - if(nullptr == mTelemetryMetricsObject) /*mTelemetryMetricsObject is null retry to create*/ - { - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - switch(currentAction) - { - case AppManagerImplementation::APP_ACTION_LAUNCH: - case AppManagerImplementation::APP_ACTION_PRELOAD: - markerName = TELEMETRY_MARKER_LAUNCH_ERROR; - break; - case AppManagerImplementation::APP_ACTION_CLOSE: - case AppManagerImplementation::APP_ACTION_TERMINATE: - case AppManagerImplementation::APP_ACTION_KILL: - markerName = TELEMETRY_MARKER_CLOSE_ERROR; - break; - default: - LOGERR("currentAction is invalid"); - break; - } - - if(!markerName.empty() && (nullptr != mTelemetryMetricsObject)) - { - jsonParam["errorCode"] = (int)errorCode; - jsonParam.ToString(telemetryMetrics); - if(!telemetryMetrics.empty()) - { - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - mTelemetryMetricsObject->Publish(appId, markerName); - } - } - } - -} /* namespace Plugin */ -} /* namespace WPEFramework */ - diff --git a/AppManager/AppManagerTelemetryReporting.h b/AppManager/AppManagerTelemetryReporting.h deleted file mode 100755 index 2dd487b..0000000 --- a/AppManager/AppManagerTelemetryReporting.h +++ /dev/null @@ -1,61 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "AppManagerImplementation.h" -#include - -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#define TELEMETRY_MARKER_LAUNCH_ERROR "AppLaunchError_split" -#define TELEMETRY_MARKER_CLOSE_TIME "AppCloseTime_split" -#define TELEMETRY_MARKER_CLOSE_ERROR "AppCloseError_split" -#define TELEMETRY_MARKER_APP_CRASHED "AppCrashed_split" - -namespace WPEFramework -{ -namespace Plugin -{ - -class AppManagerTelemetryReporting -{ - public /*methods*/: - AppManagerTelemetryReporting(const AppManagerTelemetryReporting&) = delete; - AppManagerTelemetryReporting& operator=(const AppManagerTelemetryReporting&) = delete; - static AppManagerTelemetryReporting& getInstance(); - time_t getCurrentTimestamp(); - void reportTelemetryData(const std::string& appId, AppManagerImplementation::CurrentAction currentAction); - void reportTelemetryDataOnStateChange(const string& appId, const Exchange::ILifecycleManager::LifecycleState newState); - void reportTelemetryErrorData(const std::string& appId, AppManagerImplementation::CurrentAction currentAction, AppManagerImplementation::CurrentActionError errorCode); - void initialize(PluginHost::IShell* service); - - private /*methods*/: - AppManagerTelemetryReporting(); - ~AppManagerTelemetryReporting(); - Core::hresult createTelemetryMetricsPluginObject(); - - private /*members*/: - mutable Core::CriticalSection mAdminLock; - Exchange::ITelemetryMetrics* mTelemetryMetricsObject; - PluginHost::IShell* mCurrentservice; -}; - -} /* namespace Plugin */ -} /* namespace WPEFramework */ - diff --git a/AppManager/CMakeLists.txt b/AppManager/CMakeLists.txt deleted file mode 100755 index adf371d..0000000 --- a/AppManager/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME AppManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_APP_MANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_APP_MANAGER_AUTOSTART false CACHE STRING "Automatically start AppManager plugin") -set(PLUGIN_APP_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_APP_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start AppManager plugin") -option(AIMANAGERS_TELEMETRY_METRICS_SUPPORT "AIMANAGERS_TELEMETRY_METRICS_SUPPORT" OFF) - -add_definitions(-DAPP_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DAPP_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DAPP_MANAGER_API_VERSION_NUMBER_PATCH=0) - -set(APP_MANAGER_IMPLEMENTATION ${PLUGIN_NAME}Implementation) -add_definitions(-DPLUGIN_APP_MANAGER_IMPLEMENTATION_NAME="${APP_MANAGER_IMPLEMENTATION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - AppManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(AppManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -set(PLUGIN_APP_MANAGER_IMPLEMENTATION_SOURCES - AppManagerImplementation.cpp - LifecycleInterfaceConnector.cpp - Module.cpp) - -if (AIMANAGERS_TELEMETRY_METRICS_SUPPORT) -list( APPEND PLUGIN_APP_MANAGER_IMPLEMENTATION_SOURCES - AppManagerTelemetryReporting.cpp -) -add_definitions(-DENABLE_AIMANAGERS_TELEMETRY_METRICS) -endif (AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - ${PLUGIN_APP_MANAGER_IMPLEMENTATION_SOURCES} -) - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set(APP_MANAGER_INCLUDES $ENV{APP_MANAGER_INCLUDES}) -separate_arguments(APP_MANAGER_INCLUDES) -include_directories(BEFORE ${APP_MANAGER_INCLUDES}) -if (RDK_SERVICES_L1_TEST) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,stat) -endif (RDK_SERVICES_L1_TEST) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_APP_MANAGER_EXTRA_LIBRARIES}) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/AppManager/LifecycleInterfaceConnector.cpp b/AppManager/LifecycleInterfaceConnector.cpp deleted file mode 100755 index e42fbae..0000000 --- a/AppManager/LifecycleInterfaceConnector.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" -#include "LifecycleInterfaceConnector.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "AppManagerImplementation.h" -#include "UtilsString.h" -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include "AppManagerTelemetryReporting.h" -#endif - -#define SUSPEND_POLICY_FILE "/tmp/AI2.0Suspendable" -#define HIBERNATE_POLICY_FILE "/tmp/AI2.0Hibernatable" -#define PAUSE_STATE_WAITTIME 1000 - -using namespace std; -using namespace Utils; - -namespace WPEFramework -{ - namespace Plugin - { - LifecycleInterfaceConnector* LifecycleInterfaceConnector::_instance = nullptr; - static uint32_t gAppsActiveCounter = 0; - - LifecycleInterfaceConnector::LifecycleInterfaceConnector(PluginHost::IShell* service) - : mLifecycleManagerRemoteObject(nullptr), - mLifecycleManagerStateRemoteObject(nullptr), - mNotification(*this), - mAppStateChangeNotification(*this), - mCurrentservice(nullptr), - mAppIdAwaitingPause("") - { - LOGINFO("Create LifecycleInterfaceConnector Instance"); - LifecycleInterfaceConnector::_instance = this; - if (service != nullptr) - { - mCurrentservice = service; - mCurrentservice->AddRef(); - } - } - - LifecycleInterfaceConnector::~LifecycleInterfaceConnector() - { - if (nullptr != mCurrentservice) - { - mCurrentservice->Release(); - mCurrentservice = nullptr; - } - LifecycleInterfaceConnector::_instance = nullptr; - - //clear action list - mAppCurrentActionList.clear(); - } - - Core::hresult LifecycleInterfaceConnector::createLifecycleManagerRemoteObject() - { - Core::hresult status = Core::ERROR_GENERAL; - - if (nullptr == mCurrentservice) - { - LOGWARN("mCurrentservice is null \n"); - } - else if (nullptr == (mLifecycleManagerRemoteObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.LifecycleManager"))) - { - LOGWARN("Failed to create LifecycleManager Remote object\n"); - } - else if (nullptr == (mLifecycleManagerStateRemoteObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.LifecycleManager"))) - { - LOGWARN("Failed to create LifecycleManagerState Remote object\n"); - } - else - { - LOGINFO("Created LifecycleManager Remote Object \n"); - mLifecycleManagerRemoteObject->AddRef(); - mLifecycleManagerRemoteObject->Register(&mAppStateChangeNotification); - - LOGINFO("Created LifecycleManagerState Remote Object \n"); - mLifecycleManagerStateRemoteObject->AddRef(); - mLifecycleManagerStateRemoteObject->Register(&mNotification); - LOGINFO("LifecycleManagerState notification registered"); - - status = Core::ERROR_NONE; - } - return status; - } - - void LifecycleInterfaceConnector::releaseLifecycleManagerRemoteObject() - { - ASSERT(nullptr != mLifecycleManagerRemoteObject ); - if(mLifecycleManagerRemoteObject ) - { - mLifecycleManagerRemoteObject->Unregister(&mAppStateChangeNotification); - mLifecycleManagerRemoteObject ->Release(); - mLifecycleManagerRemoteObject = nullptr; - } - - ASSERT(nullptr != mLifecycleManagerStateRemoteObject ); - if(mLifecycleManagerStateRemoteObject ) - { - mLifecycleManagerStateRemoteObject->Unregister(&mNotification); - mLifecycleManagerStateRemoteObject ->Release(); - mLifecycleManagerStateRemoteObject = nullptr; - } - } - - Core::hresult LifecycleInterfaceConnector::isAppLoaded(const string& appId, bool& loaded) - { - Core::hresult status = Core::ERROR_GENERAL; - mAdminLock.Lock(); - /* Checking if mLifecycleManagerRemoteObject is not valid then create the object */ - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - ASSERT (nullptr != mLifecycleManagerRemoteObject); - - if (nullptr != mLifecycleManagerRemoteObject) - { - status = mLifecycleManagerRemoteObject->IsAppLoaded(appId, loaded); - } - mAdminLock.Unlock(); - return status; - } - - -/* - * @brief LaunchApp invokes this to call LifecycleManager API. - * @Params : const string& appId , const string& intent , const string& launchArgs - * @return : Core::hresult - */ - Core::hresult LifecycleInterfaceConnector::launch(const string& appId, const string& intent, const string& launchArgs, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject) - { - Core::hresult status = Core::ERROR_GENERAL; - AppManagerImplementation*appManagerImplInstance = AppManagerImplementation::getInstance(); - bool loaded = false; - string appInstanceId = ""; - string errorReason = ""; - bool success = true; - Exchange::ILifecycleManager::LifecycleState state = Exchange::ILifecycleManager::LifecycleState::UNLOADED; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - - if (appId.empty()) - { - LOGERR("appId is empty"); - } - else - { - mAdminLock.Lock(); - /* Checking if mLifecycleManagerRemoteObject is not valid then create the object */ - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - ASSERT (nullptr != mLifecycleManagerRemoteObject); - - if (nullptr != mLifecycleManagerRemoteObject) - { - status = isAppLoaded(appId, loaded); - if (appManagerImplInstance != nullptr) - { - auto it = appManagerImplInstance->mAppInfo.find(appId); - if ((loaded == true) && - (Core::ERROR_NONE == status) && - (it != appManagerImplInstance->mAppInfo.end()) && - (it->second.appNewState == Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED)) - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_RESUME); - state = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - LOGINFO("launchApp appInstanceId %s", it->second.appInstanceId.c_str()); - status = mLifecycleManagerRemoteObject->SetTargetAppState(it->second.appInstanceId, state, intent); - - if (status == Core::ERROR_NONE) - { - LOGINFO("Update App Info"); - it->second.targetAppState = Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - it->second.appIntent = intent; - } - else - { - LOGERR("SetTargetAppState Failed"); - } - } - else - { - if (fileExists(SUSPEND_POLICY_FILE) == true) - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_SUSPEND); - state = Exchange::ILifecycleManager::LifecycleState::SUSPENDED; - } - else - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_LAUNCH); - state = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - string source = ""; - appManagerImplInstance->handleOnAppLaunchRequest(appId, intent, source); - } - LOGINFO("spawnApp called ,state %u",state); - status = mLifecycleManagerRemoteObject->SpawnApp(appId, intent, state, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success); - - if (status == Core::ERROR_NONE) - { - LOGINFO("Update App Info"); - it->second.appInstanceId = std::move(appInstanceId); - it->second.appIntent = intent; - it->second.packageInfo.type = AppManagerImplementation::APPLICATION_TYPE_INTERACTIVE; - it->second.targetAppState = (state == Exchange::ILifecycleManager::LifecycleState::SUSPENDED) - ? Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED - : Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - } - else - { - LOGERR("spawnApp failed"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_SPAWN_APP); -#endif - } - } - } - else - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - } - else - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_LAUNCH, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - mAdminLock.Unlock(); - } - return status; - } - - /* PreloadApp invokes it */ - Core::hresult LifecycleInterfaceConnector::preLoadApp(const string& appId, const string& launchArgs, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, string& error) - { - Core::hresult status = Core::ERROR_GENERAL; - AppManagerImplementation *appManagerImplInstance = AppManagerImplementation::getInstance(); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - - string intent = ""; - - string appInstanceId = ""; - bool success = true; - Exchange::ILifecycleManager::LifecycleState state = Exchange::ILifecycleManager::LifecycleState::UNLOADED; - if (appId.empty()) - { - LOGERR("appId is empty"); - } - else - { - mAdminLock.Lock(); - /* Checking if mLifecycleManagerRemoteObject is not valid then create the object */ - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - ASSERT (nullptr != mLifecycleManagerRemoteObject); - if (nullptr != mLifecycleManagerRemoteObject) - { - if (fileExists(SUSPEND_POLICY_FILE) == true) - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_SUSPEND); - state = Exchange::ILifecycleManager::LifecycleState::SUSPENDED; - } - else - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_PRELOAD); - state = Exchange::ILifecycleManager::LifecycleState::PAUSED; - } - status = mLifecycleManagerRemoteObject->SpawnApp(appId, intent, state, runtimeConfigObject, launchArgs, appInstanceId, error, success); - if (status == Core::ERROR_NONE) - { - LOGINFO("Update App Info"); - - /*Insert/update loaded app info*/ - if (nullptr != appManagerImplInstance) - { - appManagerImplInstance->mAppInfo[appId].appInstanceId = std::move(appInstanceId); - appManagerImplInstance->mAppInfo[appId].packageInfo.type = AppManagerImplementation::APPLICATION_TYPE_INTERACTIVE; - appManagerImplInstance->mAppInfo[appId].targetAppState = (state == Exchange::ILifecycleManager::LifecycleState::SUSPENDED) - ? Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED - : Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - } - } - else - { - LOGERR("PreLoad failed"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_PRELOAD, AppManagerImplementation::ERROR_SPAWN_APP); -#endif - } - } - else - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_PRELOAD, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - mAdminLock.Unlock(); - } - return status; - } - - /* Close App invokes it */ - Core::hresult LifecycleInterfaceConnector::closeApp(const string& appId) - { - uint32_t status = Core::ERROR_GENERAL; - std::string appInstanceId = ""; - std::string appIntent = ""; - AppManagerImplementation* appManagerImplInstance = AppManagerImplementation::getInstance(); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - bool isAppLoaded = false; - - LOGINFO("AppId retrieved: %s", appId.c_str()); - mAdminLock.Lock(); - - if(nullptr != appManagerImplInstance) - { - for(auto appIterator = appManagerImplInstance->mAppInfo.begin(); appIterator != appManagerImplInstance->mAppInfo.end(); ++appIterator) - { - if(appIterator->first.compare(appId) == 0) - { - appInstanceId = appIterator->second.appInstanceId; - appIntent = appIterator->second.appIntent; - isAppLoaded = true; - - if(nullptr != mLifecycleManagerRemoteObject) - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_CLOSE); - - mAppCurrentActionList[appId] = Exchange::IAppManager::AppLifecycleState::APP_STATE_TERMINATING; - - status = mLifecycleManagerRemoteObject->SetTargetAppState(appInstanceId, Exchange::ILifecycleManager::LifecycleState::PAUSED, appIntent); - - if(status == Core::ERROR_NONE) - { - LOGINFO("Requested PAUSED state for appId: %s. Waiting for PAUSED confirmation...", appId.c_str()); - - mAppIdAwaitingPause = appId; - mAdminLock.Unlock(); - { - std::unique_lock lk(mStateMutex); - mStateChangedCV.wait_for(lk, std::chrono::milliseconds(PAUSE_STATE_WAITTIME)); - } - - mAdminLock.Lock(); - auto it = appManagerImplInstance->mAppInfo.find(appId); - if(it != appManagerImplInstance->mAppInfo.end() && - it->second.appNewState == Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED) - { - mAppIdAwaitingPause.clear(); - - auto retryIt = appManagerImplInstance->mAppInfo.find(appId); - if (retryIt != appManagerImplInstance->mAppInfo.end()) - { - // Check for install/uninstall block. - bool installUninstallBlocked = appManagerImplInstance->checkInstallUninstallBlock(appId); - if (installUninstallBlocked) - { - LOGINFO("Blocked state found for appId: %s. Initiating TERMINATE.", appId.c_str()); - mAdminLock.Unlock(); - Core::hresult terminateStatus = appManagerImplInstance->TerminateApp(appId); - LOGINFO("TerminateApp returned status: %d", terminateStatus); - mAdminLock.Lock(); - } - /* Found the AppInfo; apply suspend/hibernate/unload logic */ - else if (fileExists(SUSPEND_POLICY_FILE)) - { - LOGINFO("App with AppId: %s is suspendable", appId.c_str()); - retryIt->second.targetAppState = Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED; - status = mLifecycleManagerRemoteObject->SetTargetAppState(appInstanceId, Exchange::ILifecycleManager::LifecycleState::SUSPENDED, appIntent); - - if (status == Core::ERROR_NONE && fileExists(HIBERNATE_POLICY_FILE)) - { - LOGINFO("App with AppId: %s is hibernatable", appId.c_str()); - retryIt->second.targetAppState = Exchange::IAppManager::AppLifecycleState::APP_STATE_HIBERNATED; - status = mLifecycleManagerRemoteObject->SetTargetAppState(appInstanceId, Exchange::ILifecycleManager::LifecycleState::HIBERNATED, appIntent); - - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to apply hibernate policy for appId: %s", appId.c_str()); - } - } - else if (status != Core::ERROR_NONE) - { - LOGERR("Failed to apply suspend policy for appId: %s", appId.c_str()); - } - } - else - { - LOGINFO("App with AppId: %s is non suspendable. Keeping app in Paused state", appId.c_str()); - } - } - else - { - LOGERR("AppId: %s not found after PAUSED wait", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INTERNAL); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("Timed out waiting for appId: %s to reach PAUSED state", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INTERNAL); -#endif - status = Core::ERROR_GENERAL; - } - } - else - { - LOGERR("Failed to set PAUSED state for AppId: %s", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_SET_TARGET_APP_STATE); -#endif - } - } - else - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - - break; - } - } - - if (!isAppLoaded) - { - LOGERR("AppId %s not found in database", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INVALID_PARAMS); -#endif - } - } - else - { - LOGERR("AppManagerImplementation instance is null"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_CLOSE, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - mAdminLock.Unlock(); - return status; - } - - /* Terminate App invokes it */ - Core::hresult LifecycleInterfaceConnector::terminateApp(const string& appId) - { - uint32_t status = Core::ERROR_GENERAL; - std::string appInstanceId = ""; - AppManagerImplementation* appManagerImplInstance = AppManagerImplementation::getInstance(); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - bool success = false; - std::string errorReason = ""; - bool foundAppId = false; - - /* Retrieve the appId from the parameters object */ - LOGINFO("AppId retrieved: %s", appId.c_str()); - - mAdminLock.Lock(); - if (nullptr != appManagerImplInstance) - { - for ( std::map::iterator appIterator = appManagerImplInstance->mAppInfo.begin(); appIterator != appManagerImplInstance->mAppInfo.end(); appIterator++) - { - if (appIterator->first.compare(appId) == 0) - { - foundAppId = true; - appInstanceId = appIterator->second.appInstanceId; - if (nullptr != mLifecycleManagerRemoteObject) - { - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_TERMINATE); - mAppCurrentActionList[appId] = Exchange::IAppManager::AppLifecycleState::APP_STATE_TERMINATING; - status = mLifecycleManagerRemoteObject->UnloadApp(appInstanceId, errorReason, success); - if (status != Core::ERROR_NONE) - { - LOGERR("UnloadApp failed with error reason: %s", errorReason.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_TERMINATE, AppManagerImplementation::ERROR_UNLOAD_APP); -#endif - } - } - break; - } - } - if (!foundAppId) - { - LOGERR("AppId %s not found in database", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_TERMINATE, AppManagerImplementation::ERROR_INVALID_PARAMS); -#endif - } - } - else - { - LOGERR("appManagerImplInstance is null"); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_TERMINATE, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - mAdminLock.Unlock(); - return status; - } - - /* Kill App invokes it */ - Core::hresult LifecycleInterfaceConnector::killApp(const string& appId) - { - LOGINFO("killApp entered"); - Core::hresult result = Core::ERROR_GENERAL; - AppManagerImplementation* appManagerImplInstance = AppManagerImplementation::getInstance(); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting& appManagerTelemetryReporting =AppManagerTelemetryReporting::getInstance(); -#endif - - if (appId.empty()) - { - LOGERR("appId is empty"); - return result; - } - - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - ASSERT (nullptr != mLifecycleManagerRemoteObject); - if (nullptr != mLifecycleManagerRemoteObject) - { - mAdminLock.Lock(); - string appInstanceId = GetAppInstanceId(appId); - if (appInstanceId.empty()) - { - LOGERR("appInstanceId not found for appId '%s'", appId.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_KILL, AppManagerImplementation::ERROR_INVALID_PARAMS); -#endif - } - else - { - string errorReason{}; - bool success{}; - - appManagerImplInstance->updateCurrentAction(appId, AppManagerImplementation::APP_ACTION_KILL); - mAppCurrentActionList[appId] = Exchange::IAppManager::AppLifecycleState::APP_STATE_TERMINATING; - result = mLifecycleManagerRemoteObject->KillApp(appInstanceId, errorReason, success); - - if (!(result == Core::ERROR_NONE && success)) - { - LOGERR("killApp failed, result: %d, success: %d, errorReason: %s", result, success, errorReason.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_KILL, AppManagerImplementation::ERROR_KILL_APP); -#endif - } - } - mAdminLock.Unlock(); - } - else - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appManagerTelemetryReporting.reportTelemetryErrorData(appId, AppManagerImplementation::APP_ACTION_KILL, AppManagerImplementation::ERROR_INTERNAL); -#endif - } - - return result; - } - - /* Send Intent invokes it */ - Core::hresult LifecycleInterfaceConnector::sendIntent(const string& appId, const string& intent) - { - LOGINFO("sendIntent Entered"); - Core::hresult result = Core::ERROR_GENERAL; - - if (appId.empty()) - { - LOGERR("appId is empty"); - return result; - } - - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - - if (nullptr != mLifecycleManagerRemoteObject) - { - mAdminLock.Lock(); - string appInstanceId = GetAppInstanceId(appId); - if (appInstanceId.empty()) - { - LOGERR("appInstanceId not found for appId '%s'", appId.c_str()); - } - else - { - string errorReason{}; - bool success{}; - - result = mLifecycleManagerRemoteObject->SendIntentToActiveApp(appInstanceId, intent, errorReason, success); - - if (!(result == Core::ERROR_NONE && success)) - { - LOGERR("sentIntent failed, result: %d, success: %d, errorReason: %s", result, success, errorReason.c_str()); - } - } - mAdminLock.Unlock(); - } - - return result; - } - - /* GetLoadedApps invokes it */ - Core::hresult LifecycleInterfaceConnector::getLoadedApps(Exchange::IAppManager::ILoadedAppInfoIterator*& apps) - { - LOGINFO("getLoadedApps Entered"); - Core::hresult result = Core::ERROR_GENERAL; - AppManagerImplementation *appManagerImplInstance = AppManagerImplementation::getInstance(); - std::list loadedAppInfoList; - - mAdminLock.Lock(); - /* Checking if mLifecycleManagerRemoteObject is not valid then create the object */ - if (nullptr == mLifecycleManagerRemoteObject) - { - LOGINFO("Create LifecycleManager Remote store object"); - if (Core::ERROR_NONE != createLifecycleManagerRemoteObject()) - { - LOGERR("Failed to create LifecycleInterfaceConnector"); - } - } - - ASSERT (nullptr != mLifecycleManagerRemoteObject); - if (nullptr != mLifecycleManagerRemoteObject) - { - JsonArray loadedAppsArray; - string loadedApps = ""; - LOGINFO("Get Loaded Apps"); - result = mLifecycleManagerRemoteObject->GetLoadedApps(false, loadedApps); - // Parse the string into a JSON array - JsonArray loadedAppsJsonArray; - if ((result != Core::ERROR_NONE) || loadedApps.empty() || !loadedAppsJsonArray.FromString(loadedApps)) - { - LOGERR("GetLoadedApps call: %s", (result != Core::ERROR_NONE) ? "Failed" : (loadedApps.empty() ? "returned empty list" : "format not a JSON string")); - goto End; - } - else - { - LOGINFO("GetLoadedApps succeeded: %s", loadedApps.c_str()); - } - - auto getIntJsonField = [&](JsonObject& obj, const char* key) -> int { - return obj.HasLabel(key) ? static_cast(obj[key].Number()) : 0; - }; - - // Iterate through each app JSON object in the array - for (size_t i = 0; i < loadedAppsJsonArray.Length(); ++i) - { - JsonObject loadedAppsObject = loadedAppsJsonArray[i].Object(); - string appId = loadedAppsObject.HasLabel("appId")?loadedAppsObject["appId"].String():""; - LOGINFO("Loaded appId: %s", appId.c_str()); - auto& appInfo = appManagerImplInstance->mAppInfo[appId]; - - Exchange::IAppManager::LoadedAppInfo loadedAppInfo = {}; - loadedAppInfo.appId = appId; - loadedAppInfo.type = appManagerImplInstance->getInstallAppType(appInfo.packageInfo.type); - loadedAppInfo.appInstanceId = appInfo.appInstanceId = loadedAppsObject.HasLabel("appInstanceID")?loadedAppsObject["appInstanceID"].String():""; - loadedAppInfo.activeSessionId = appInfo.activeSessionId = loadedAppsObject.HasLabel("activeSessionId")?loadedAppsObject["activeSessionId"].String():""; - - appInfo.targetAppState = mapAppLifecycleState( - static_cast( - getIntJsonField(loadedAppsObject, "targetLifecycleState"))); - loadedAppInfo.targetLifecycleState = appInfo.targetAppState; - appInfo.appNewState = mapAppLifecycleState( - static_cast( - getIntJsonField(loadedAppsObject, "lifecycleState"))); - loadedAppInfo.lifecycleState = appInfo.appNewState; - - //Add loaded info - loadedAppInfoList.push_back(loadedAppInfo); - } - - apps = Core::Service> \ - ::Create(loadedAppInfoList); - result = Core::ERROR_NONE; - } - else - { - LOGERR("mLifecycleManagerRemoteObject is nullptr"); - } -End: - mAdminLock.Unlock(); - return result; - } - - Exchange::IAppManager::AppLifecycleState WPEFramework::Plugin::LifecycleInterfaceConnector::mapAppLifecycleState(Exchange::ILifecycleManager::LifecycleState state) - { - Exchange::IAppManager::AppLifecycleState result = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - switch(state) - { - case Exchange::ILifecycleManager::LifecycleState::UNLOADED: - LOGINFO("UNLOADED state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - break; - case Exchange::ILifecycleManager::LifecycleState::LOADING: - LOGINFO("LOADING state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_LOADING; - break; - case Exchange::ILifecycleManager::LifecycleState::ACTIVE: - LOGINFO("ACTIVE state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - break; - case Exchange::ILifecycleManager::LifecycleState::PAUSED: - LOGINFO("PAUSED state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - break; - case Exchange::ILifecycleManager::LifecycleState::INITIALIZING: - LOGINFO("INITIALIZING state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_INITIALIZING; - break; - case Exchange::ILifecycleManager::LifecycleState::SUSPENDED: - LOGINFO("SUSPENDED state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED; - break; - case Exchange::ILifecycleManager::LifecycleState::TERMINATING: - LOGINFO("TERMINATING state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_TERMINATING; - break; - case Exchange::ILifecycleManager::LifecycleState::HIBERNATED: - LOGINFO("HIBERNATED state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_HIBERNATED; - break; - default: - LOGWARN("Unknown state %u", state); - result = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - break; - } - return result; - } - - void LifecycleInterfaceConnector::OnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::ILifecycleManager::LifecycleState oldState, const Exchange::ILifecycleManager::LifecycleState newState, const string& navigationIntent) - { - AppManagerImplementation*appManagerImplInstance = AppManagerImplementation::getInstance(); - Exchange::IAppManager::AppLifecycleState oldAppState = mapAppLifecycleState(oldState); - Exchange::IAppManager::AppLifecycleState newAppState = mapAppLifecycleState(newState); - bool shouldNotify = false; - - LOGINFO("OnAppLifecycleStateChanged event triggered ***\n"); - - if (newAppState == Exchange::IAppManager::APP_STATE_UNKNOWN || - oldAppState == Exchange::IAppManager::APP_STATE_UNKNOWN) - { - LOGINFO("Skipping notification: new or old app state is UNKNOWN"); - return; - } - - if(nullptr != appManagerImplInstance) - { - Core::SafeSyncType lock(mAdminLock); - std::map::iterator it; - for (it = appManagerImplInstance->mAppInfo.begin(); it != appManagerImplInstance->mAppInfo.end(); ++it) - { - if((it->first.compare(appId) == 0) && (it->second.appInstanceId.compare(appInstanceId) == 0)) - { - it->second.appOldState = oldAppState; - it->second.appNewState = newAppState; - it->second.appLifecycleState = newState; - it->second.appIntent = navigationIntent; - - if (oldState == Exchange::ILifecycleManager::LifecycleState::ACTIVE || - newState == Exchange::ILifecycleManager::LifecycleState::ACTIVE) - { - struct timespec stateChangeTime; - if (timespec_get(&stateChangeTime, TIME_UTC) != 0) - { - it->second.lastActiveStateChangeTime = stateChangeTime; - } - else - { - LOGERR("Unable to update the active state change time for appInstanceId: %s", appInstanceId.c_str()); - } - } - - if (newState == Exchange::ILifecycleManager::LifecycleState::ACTIVE) - { - gAppsActiveCounter++; - it->second.lastActiveIndex = gAppsActiveCounter; - } - if (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED) - { - if (appId == mAppIdAwaitingPause) - { - std::lock_guard lk(mStateMutex); - mStateChangedCV.notify_all(); - } - } - break; - } - } - shouldNotify = ((newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_LOADING) || - (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE) || - (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED) || - (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED) || - (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_HIBERNATED) || - (newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED)); - - LOGINFO("shouldNotify %d for Appstate %u",shouldNotify, newAppState); - - if(shouldNotify) - { - if(newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED) - { - if (mAppCurrentActionList[appId] == Exchange::IAppManager::AppLifecycleState::APP_STATE_TERMINATING) - { - //Normal close: Unlode event from App manager - LOGINFO("Terminate event from plugin"); - appManagerImplInstance->handleOnAppLifecycleStateChanged(appId, appInstanceId, newAppState, oldAppState, Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE); - } - else - { - //Upnormal close: No unload event from app manager - LOGINFO("Terminate event due to app crash"); - appManagerImplInstance->handleOnAppLifecycleStateChanged(appId, appInstanceId, newAppState, oldAppState, Exchange::IAppManager::AppErrorReason::APP_ERROR_ABORT); - } - mAppCurrentActionList.erase(appId); - } - else - { - appManagerImplInstance->handleOnAppLifecycleStateChanged(appId, appInstanceId, newAppState, oldAppState, Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE); - } - } - - if(newAppState == Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED) - { - appManagerImplInstance->handleOnAppUnloaded(appId, appInstanceId); - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - AppManagerTelemetryReporting::getInstance().reportTelemetryDataOnStateChange(appId, newState); -#endif - } - } - - void LifecycleInterfaceConnector::OnAppStateChanged(const string& appId, Exchange::ILifecycleManager::LifecycleState state, const string& errorReason) - { - string appInstanceId = ""; - Exchange::IAppManager::AppLifecycleState currentAppState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - AppManagerImplementation*appManagerImplInstance = AppManagerImplementation::getInstance(); - Exchange::IAppManager::AppErrorReason errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - LOGINFO("OnAppStateChanged event triggered for appId %s: state=%d, errorReason=%s", appId.c_str(), static_cast(state), errorReason.c_str()); - - if(nullptr == appManagerImplInstance) - { - LOGERR("Invalid AppManager Implementation Instance"); - } - else - { - if (!appId.empty()) - { - auto it = appManagerImplInstance->mAppInfo.find(appId); - if(it != appManagerImplInstance->mAppInfo.end()) - { - appInstanceId = it->second.appInstanceId; - currentAppState = it->second.appNewState; - } - else - { - LOGERR("appId not found in database"); - } - } - - if (!errorReason.empty()) - { - errorCode = mapErrorReason(errorReason); - appManagerImplInstance->handleOnAppLifecycleStateChanged(appId, appInstanceId, Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED, - currentAppState, errorCode); - LOGINFO("Notified error event for appId %s: currentAppState=%d errorCode %d", appId.c_str(), static_cast(currentAppState), static_cast(errorCode)); - } - } - } - - Exchange::IAppManager::AppErrorReason LifecycleInterfaceConnector::mapErrorReason(const string& errorReason) - { - Exchange::IAppManager::AppErrorReason errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - if(!errorReason.empty()) - { - if(!errorReason.compare("ERROR_CREATE_DISPLAY")) - { - errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_CREATE_DISPLAY; - } - else if(!errorReason.compare("ERROR_DOBBY_SPEC")) - { - errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_DOBBY_SPEC; - } - else if(!errorReason.compare("ERROR_INVALID_PARAM")) - { - errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_INVALID_PARAM; - } - else - { - errorCode = Exchange::IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - } - } - return errorCode; - } - - /* Returns appInstanceId for appId. Does not synchronize access to LoadedAppInfo. - * Caller should take care about the synchronization. - */ - string LifecycleInterfaceConnector::GetAppInstanceId(const string& appId) const - { - AppManagerImplementation* appManagerImpl = AppManagerImplementation::getInstance(); - if (!appManagerImpl) - return {}; - - auto it = appManagerImpl->mAppInfo.find(appId); - if (it == appManagerImpl->mAppInfo.end()) - return {}; - else - return it->second.appInstanceId; - } - - void LifecycleInterfaceConnector::removeAppInfoByAppId(const string& appId) - { - AppManagerImplementation* appManagerImpl = AppManagerImplementation::getInstance(); - if (!appManagerImpl) - return; - - auto it = appManagerImpl->mAppInfo.find(appId); - if (it != appManagerImpl->mAppInfo.end()) - { - LOGINFO("appId %s is removed from database", appId.c_str()); - appManagerImpl->mAppInfo.erase(it); - } - else - { - LOGERR("AppInfo for appId '%s' not found", appId.c_str()); - } - } - - bool LifecycleInterfaceConnector::fileExists(const char* pFileName) - { - bool isRegular = false; - - if (pFileName != nullptr) - { - struct stat fileStat; - if (stat(pFileName, &fileStat) == 0) - { - if (S_ISREG(fileStat.st_mode)) - { - isRegular = true; - LOGINFO("File: '%s' exists", pFileName); - } - else - { - LOGINFO("File: '%s' exists but is not a regular file", pFileName); - } - } - else - { - LOGINFO("File: Failed to stat file '%s'", pFileName); - } - } - else - { - LOGINFO("Filename pointer is null"); - } - - return isRegular; - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/AppManager/LifecycleInterfaceConnector.h b/AppManager/LifecycleInterfaceConnector.h deleted file mode 100755 index 3e320f1..0000000 --- a/AppManager/LifecycleInterfaceConnector.h +++ /dev/null @@ -1,123 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - class LifecycleInterfaceConnector - { - private: - class NotificationHandler : public Exchange::ILifecycleManagerState::INotification { - - public: - NotificationHandler(LifecycleInterfaceConnector& parent) : mParent(parent){} - ~NotificationHandler(){} - - void OnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::ILifecycleManager::LifecycleState oldState, const Exchange::ILifecycleManager::LifecycleState newState, const string& navigationIntent) - { - mParent.OnAppLifecycleStateChanged(appId, appInstanceId, oldState, newState, navigationIntent); - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(Exchange::ILifecycleManagerState::INotification) - END_INTERFACE_MAP - - private: - LifecycleInterfaceConnector& mParent; - }; - class AppStateChangeNotificationHandler : public Exchange::ILifecycleManager::INotification { - - public: - AppStateChangeNotificationHandler(LifecycleInterfaceConnector& parent) : mParent(parent){} - ~AppStateChangeNotificationHandler(){} - - void OnAppStateChanged(const string& appId, Exchange::ILifecycleManager::LifecycleState state, const string& errorReason) - { - mParent.OnAppStateChanged(appId, state, errorReason); - } - - BEGIN_INTERFACE_MAP(AppStateChangeNotificationHandler) - INTERFACE_ENTRY(Exchange::ILifecycleManager::INotification) - END_INTERFACE_MAP - - private: - LifecycleInterfaceConnector& mParent; - }; - - public/*members*/: - static LifecycleInterfaceConnector* _instance; - - public: - LifecycleInterfaceConnector(PluginHost::IShell* service); - ~LifecycleInterfaceConnector(); - Core::hresult createLifecycleManagerRemoteObject(); - void releaseLifecycleManagerRemoteObject(); - Core::hresult launch(const string& appId, const string& intent, const string& launchArgs, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject); - Core::hresult preLoadApp(const string& appId, const string& launchArgs, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, string& error); - Core::hresult closeApp(const string& appId); - Core::hresult terminateApp(const string& appId); - Core::hresult killApp(const string& appId); - Core::hresult sendIntent(const string& appId, const string& intent); - Core::hresult getLoadedApps(Exchange::IAppManager::ILoadedAppInfoIterator*& apps); - void OnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::ILifecycleManager::LifecycleState newState, const Exchange::ILifecycleManager::LifecycleState oldState, const string& navigationIntent); - void OnAppStateChanged(const string& appId, Exchange::ILifecycleManager::LifecycleState state, const string& errorReason); - Exchange::IAppManager::AppLifecycleState mapAppLifecycleState(Exchange::ILifecycleManager::LifecycleState state); - string GetAppInstanceId(const string& appId) const; - void removeAppInfoByAppId(const string& appId); - Core::hresult isAppLoaded(const string& appId, bool& loaded); - bool fileExists(const char* pFileName); - Exchange::IAppManager::AppErrorReason mapErrorReason(const string& errorReason); - - private: - mutable Core::CriticalSection mAdminLock; - Exchange::ILifecycleManager *mLifecycleManagerRemoteObject; - Exchange::ILifecycleManagerState *mLifecycleManagerStateRemoteObject; - Core::Sink mNotification; - Core::Sink mAppStateChangeNotification; - PluginHost::IShell* mCurrentservice; - std::condition_variable mStateChangedCV; - std::mutex mStateMutex; - std::string mAppIdAwaitingPause; - std::map mAppCurrentActionList; - }; - } -} diff --git a/AppManager/Module.cpp b/AppManager/Module.cpp deleted file mode 100644 index cd6d4d1..0000000 --- a/AppManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/AppManager/Module.h b/AppManager/Module.h deleted file mode 100755 index 2a049da..0000000 --- a/AppManager/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_AppManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/AppNotifications/AppNotifications.conf.in b/AppNotifications/AppNotifications.conf.in deleted file mode 100755 index 8955a2a..0000000 --- a/AppNotifications/AppNotifications.conf.in +++ /dev/null @@ -1,5 +0,0 @@ -autostart = "@PLUGIN_APPNOTIFICATIONS_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.AppNotifications" -startuporder = "@PLUGIN_APPNOTIFICATIONS_STARTUPORDER@" - diff --git a/AppNotifications/AppNotifications.config b/AppNotifications/AppNotifications.config deleted file mode 100755 index 315bab5..0000000 --- a/AppNotifications/AppNotifications.config +++ /dev/null @@ -1,15 +0,0 @@ -set(autostart ${PLUGIN_APPNOTIFICATIONS_AUTOSTART}) - -if(PLUGIN_APPNOTIFICATIONS_STARTUPORDER) -set (startuporder ${PLUGIN_APPNOTIFICATIONS_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_APPNOTIFICATIONS_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) - diff --git a/AppNotifications/AppNotifications.cpp b/AppNotifications/AppNotifications.cpp deleted file mode 100644 index 9ad1718..0000000 --- a/AppNotifications/AppNotifications.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AppNotifications.h" -#include - - -#define API_VERSION_NUMBER_MAJOR APPNOTIFICATIONS_MAJOR_VERSION -#define API_VERSION_NUMBER_MINOR APPNOTIFICATIONS_MINOR_VERSION -#define API_VERSION_NUMBER_PATCH APPNOTIFICATIONS_PATCH_VERSION - -namespace WPEFramework { - -namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - SERVICE_REGISTRATION(AppNotifications, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - AppNotifications::AppNotifications(): mService(nullptr), mAppNotifications(nullptr), mConnectionId(0) - { - SYSLOG(Logging::Startup, (_T("AppNotifications Constructor"))); - } - - AppNotifications::~AppNotifications() - { - SYSLOG(Logging::Shutdown, (string(_T("AppNotifications Destructor")))); - } - - /* virtual */ const string AppNotifications::Initialize(PluginHost::IShell* service) - { - ASSERT(service != nullptr); - ASSERT(mAppNotifications == nullptr); - - SYSLOG(Logging::Startup, (_T("AppNotifications::Initialize: PID=%u"), getpid())); - - mService = service; - mService->AddRef(); - mAppNotifications = service->Root(mConnectionId, 2000, _T("AppNotificationsImplementation")); - - if (mAppNotifications != nullptr) { - auto configConnection = mAppNotifications->QueryInterface(); - if (configConnection != nullptr) { - configConnection->Configure(service); - configConnection->Release(); - } - } - else - { - SYSLOG(Logging::Startup, (_T("AppNotifications::Initialize: Failed to initialise AppNotifications plugin"))); - } - // On success return empty, to indicate there is no error text. - return ((mAppNotifications != nullptr)) - ? EMPTY_STRING - : _T("Could not retrieve the AppNotifications interface."); - } - - /* virtual */ void AppNotifications::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Shutdown, (string(_T("AppNotifications::Deinitialize")))); - ASSERT(service == mService); - - if (mAppNotifications != nullptr) { - RPC::IRemoteConnection *connection(service->RemoteConnection(mConnectionId)); - VARIABLE_IS_NOT_USED uint32_t result = mAppNotifications->Release(); - mAppNotifications = nullptr; - - // It should have been the last reference we are releasing, - // so it should end up in a DESCRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (connection != nullptr) - { - // Lets trigger a cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :~) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mService->Release(); - mService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("AppNotifications de-initialised")))); - } - - void AppNotifications::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) { - - ASSERT(mService != nullptr); - - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - -} // namespace Plugin -} // namespace WPEFramework \ No newline at end of file diff --git a/AppNotifications/AppNotifications.h b/AppNotifications/AppNotifications.h deleted file mode 100644 index 2dcd7be..0000000 --- a/AppNotifications/AppNotifications.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "Module.h" -#include - - -namespace WPEFramework { - - namespace Plugin { - - - // This is a server for a JSONRPC communication channel. - // For a plugin to be capable to handle JSONRPC, inherit from PluginHost::JSONRPC. - // By inheriting from this class, the plugin realizes the interface PluginHost::IDispatcher. - // This realization of this interface implements, by default, the following methods on this plugin - // - exists - // - register - // - unregister - // Any other method to be handled by this plugin can be added can be added by using the - // templated methods Register on the PluginHost::JSONRPC class. - // As the registration/unregistration of notifications is realized by the class PluginHost::JSONRPC, - // this class exposes a public method called, Notify(), using this methods, all subscribed clients - // will receive a JSONRPC message as a notification, in case this method is called. - class AppNotifications : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - // We do not allow this plugin to be copied !! - AppNotifications(const AppNotifications&) = delete; - AppNotifications& operator=(const AppNotifications&) = delete; - - public: - AppNotifications(); - virtual ~AppNotifications(); - virtual const string Initialize(PluginHost::IShell* shell) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - - BEGIN_INTERFACE_MAP(AppNotifications) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IAppNotifications, mAppNotifications) - END_INTERFACE_MAP - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* mService; - Exchange::IAppNotifications* mAppNotifications; - uint32_t mConnectionId; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/AppNotifications/AppNotificationsImplementation.cpp b/AppNotifications/AppNotificationsImplementation.cpp deleted file mode 100644 index 0303116..0000000 --- a/AppNotifications/AppNotificationsImplementation.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include "AppNotificationsImplementation.h" -#include "UtilsLogging.h" -#include "StringUtils.h" - -namespace WPEFramework -{ - namespace Exchange { - bool operator==(const IAppNotifications::AppNotificationContext& lhs, - const IAppNotifications::AppNotificationContext& rhs) { - return lhs.requestId == rhs.requestId && - lhs.connectionId == rhs.connectionId && - lhs.appId == rhs.appId && - lhs.origin == rhs.origin; - } - } - namespace Plugin - { - SERVICE_REGISTRATION(AppNotificationsImplementation, 1, 0); - - AppNotificationsImplementation::AppNotificationsImplementation() : - mShell(nullptr), - mSubMap(*this), - mThunderManager(*this), - mEmitter(*this) - { - } - - AppNotificationsImplementation::~AppNotificationsImplementation() - { - // Cleanup resources if needed - if (mShell != nullptr) - { - mShell->Release(); - mShell = nullptr; - } - } - - Core::hresult AppNotificationsImplementation::Subscribe(const Exchange::IAppNotifications::AppNotificationContext &context /* @in */, - bool listen /* @in */, - const string &module /* @in */, - const string &event /* @in */) { - LOGTRACE("Subscribe [requestId=%d appId=%s connectionId=%d] register=%s, module=%s, event=%s", - context.requestId, context.appId.c_str(), context.connectionId, - listen ? "true" : "false", module.c_str(), event.c_str()); - if (listen) { - if (!mSubMap.Exists(module)) { - // Thunder subscription - Core::IWorkerPool::Instance().Submit(SubscriberJob::Create(this, module, event, listen)); - } - mSubMap.Add(event, context); - } else { - mSubMap.Remove(event, context); - // If all elements are removed the entry is erased automatically - // This can be used to measure unsubscribe - if (!mSubMap.Exists(event)) { - // Thunder unsubscription - Core::IWorkerPool::Instance().Submit(SubscriberJob::Create(this, module, event, listen)); - } - } - return Core::ERROR_NONE; - } - - Core::hresult AppNotificationsImplementation::Emit(const string &event /* @in */, - const string &payload /* @in @opaque */, - const string &appId /* @in */) { - LOGTRACE("Emit [event= %s payload=%s appId=%s]", - event.c_str(), payload.c_str(), appId.c_str()); - Core::IWorkerPool::Instance().Submit(EmitJob::Create(this, event, payload, appId)); - return Core::ERROR_NONE; - } - - Core::hresult AppNotificationsImplementation::Cleanup(const uint32_t connectionId /* @in */, const string &origin /* @in */) { - LOGTRACE("Cleanup [connectionId=%d origin=%s]", connectionId, origin.c_str()); - mSubMap.CleanupNotifications(connectionId, origin); - return Core::ERROR_NONE; - } - - void AppNotificationsImplementation::SubscriberMap::CleanupNotifications(const uint32_t &connectionId, const string& origin) { - std::lock_guard lock(mSubscriberMutex); - for (auto it = mSubscribers.begin(); it != mSubscribers.end(); ) { - auto& vec = it->second; - vec.erase(std::remove_if(vec.begin(), vec.end(), - [&](const Exchange::IAppNotifications::AppNotificationContext& context) { - return (context.connectionId == connectionId) && (context.origin == origin); - }), vec.end()); - if (vec.empty()) { - it = mSubscribers.erase(it); - } else { - ++it; - } - } - } - - uint32_t AppNotificationsImplementation::Configure(PluginHost::IShell *shell) - { - LOGINFO("Configuring AppNotifications"); - uint32_t result = Core::ERROR_NONE; - ASSERT(shell != nullptr); - mShell = shell; - mShell->AddRef(); - return result; - } - - void AppNotificationsImplementation::SubscriberMap::Add(const string& key, const Exchange::IAppNotifications::AppNotificationContext& context) { - string lowerKey = StringUtils::toLower(key); - std::lock_guard lock(mSubscriberMutex); - mSubscribers[lowerKey].push_back(context); - } - - void AppNotificationsImplementation::SubscriberMap::Remove(const string& key, const Exchange::IAppNotifications::AppNotificationContext& context) { - std::lock_guard lock(mSubscriberMutex); - string lowerKey = StringUtils::toLower(key); - auto it = mSubscribers.find(lowerKey); - if (it != mSubscribers.end()) { - auto& vec = it->second; - vec.erase(std::remove(vec.begin(), vec.end(), context), vec.end()); - if (vec.empty()) { - mSubscribers.erase(it); - } - } - } - - std::vector AppNotificationsImplementation::SubscriberMap::Get(const string& key) const { - std::lock_guard lock(mSubscriberMutex); - string lowerKey = StringUtils::toLower(key); - auto it = mSubscribers.find(lowerKey); - if (it != mSubscribers.end()) { - return it->second; - } - return {}; - } - - bool AppNotificationsImplementation::SubscriberMap::Exists(const string& key) const { - std::lock_guard lock(mSubscriberMutex); - string lowerKey = StringUtils::toLower(key); - auto it = mSubscribers.find(lowerKey); - return it != mSubscribers.end(); - } - - void AppNotificationsImplementation::SubscriberMap::EventUpdate(const string& key, const string& payloadStr, const string& appId ) { - - std::lock_guard lock(mSubscriberMutex); - string lowerKey = StringUtils::toLower(key); - auto it = mSubscribers.find(lowerKey); - if (it != mSubscribers.end()) { - for (const auto& context : it->second) { - // check if app id is not empty if not empty check if context.appId matches appId - if (!appId.empty()) { - - if(context.appId == appId) { - // Dispatch the event to the subscriber - Dispatch(context, payloadStr); - } - - } else { - // Dispatch the event to the subscriber - Dispatch(context, payloadStr); - } - } - } else { - // using LOGWARN print a warning that there are no active listeners for this event - LOGWARN("No active listeners for event: %s", key.c_str()); - } - } - - void AppNotificationsImplementation::SubscriberMap::Dispatch(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload) { - if (ContextUtils::IsOriginGateway(context.origin)) { - DispatchToGateway(context, payload); - } else { - DispatchToLaunchDelegate(context, payload); - } - } - - void AppNotificationsImplementation::SubscriberMap::DispatchToGateway(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload) { - if (nullptr == mAppGateway) { - mAppGateway = mParent.mShell->QueryInterfaceByCallsign(APP_GATEWAY_CALLSIGN); - if (mAppGateway == nullptr) { - LOGERR("Failed to get IAppGateway interface"); - return; - } - } - Exchange::GatewayContext gatewayContext = ContextUtils::ConvertNotificationToAppGatewayContext(context); - mAppGateway->Respond(gatewayContext, payload); - } - - void AppNotificationsImplementation::SubscriberMap::DispatchToLaunchDelegate(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload) { - if (nullptr == mInternalGatewayNotifier) { - mInternalGatewayNotifier = mParent.mShell->QueryInterfaceByCallsign(INTERNAL_GATEWAY_CALLSIGN); - if (mInternalGatewayNotifier == nullptr) { - LOGERR("Failed to get ILaunchDelegate interface"); - return; - } - } - Exchange::GatewayContext gatewayContext = ContextUtils::ConvertNotificationToAppGatewayContext(context); - mInternalGatewayNotifier->Respond(gatewayContext, payload); - } - - AppNotificationsImplementation::ThunderSubscriptionManager::~ThunderSubscriptionManager() { - // Copy notifications to avoid holding the lock during external calls - std::vector notificationsCopy; - { - std::lock_guard lock(mThunderSubscriberMutex); - notificationsCopy = mRegisteredNotifications; - mRegisteredNotifications.clear(); - } - // Unsubscribe from all registered notifications outside the lock - for (const auto& notification : notificationsCopy) { - HandleNotifier(notification.module, notification.event, false); - } - } - - void AppNotificationsImplementation::ThunderSubscriptionManager::Subscribe(const string& module, const string& event) { - // Subscribe to Thunder notifications - - // check if the notification is already registered - if (IsNotificationRegistered(module, event)) { - // log a trace message that the notification is already registered - LOGTRACE("Notification is already registered: %s", event.c_str()); - } else { - // trigger RegisterNotification - RegisterNotification(module, event); - } - } - - void AppNotificationsImplementation::ThunderSubscriptionManager::Unsubscribe(const string& module, const string& event) { - // Unsubscribe from Thunder notifications - - // check if the notification is already registered - if (IsNotificationRegistered(module, event)) { - // trigger UnregisterNotification - UnregisterNotification(module, event); - } else { - // log an error that the notification is not registered - LOGERR("Notification is not registered: %s", event.c_str()); - } - } - - bool AppNotificationsImplementation::ThunderSubscriptionManager::HandleNotifier(const string& module, const string& event, const bool& listen) { - // Check if Plugins is activated before making a request - bool status = false; - Exchange::IAppNotificationHandler *internalNotifier = mParent.mShell->QueryInterfaceByCallsign(module); - if (internalNotifier != nullptr) { - if (Core::ERROR_NONE == internalNotifier->HandleAppEventNotifier(&mParent.mEmitter, event, listen, status)) { - LOGTRACE("Notifier status for %s:%s is %s", module.c_str(), event.c_str(), status ? "true" : "false"); - } else { - LOGERR("Notification subscription failure"); - } - internalNotifier->Release(); - } else { - LOGERR("Notification Handler not available for module=%s", module.c_str()); - } - return status; - } - - void AppNotificationsImplementation::ThunderSubscriptionManager::RegisterNotification(const string& module, const string& event) { - string lowerEvent = StringUtils::toLower(event); - // call notifier and start listening - if (HandleNotifier(module, event, true)) { - std::lock_guard lock(mThunderSubscriberMutex); - mRegisteredNotifications.push_back({module, std::move(lowerEvent)}); - } - } - - void AppNotificationsImplementation::ThunderSubscriptionManager::UnregisterNotification(const string& module, const string& event) { - string lowerEvent = StringUtils::toLower(event); - if (HandleNotifier(module, lowerEvent, false)) { - std::lock_guard lock(mThunderSubscriberMutex); - mRegisteredNotifications.erase(std::remove(mRegisteredNotifications.begin(), mRegisteredNotifications.end(), NotificationKey{module, lowerEvent}), mRegisteredNotifications.end()); - } - } - - bool AppNotificationsImplementation::ThunderSubscriptionManager::IsNotificationRegistered(const string& module, const string& notification) const { - string lowerEvent = StringUtils::toLower(notification); - std::lock_guard lock(mThunderSubscriberMutex); - return std::find(mRegisteredNotifications.begin(), mRegisteredNotifications.end(), NotificationKey{module, lowerEvent}) != mRegisteredNotifications.end(); - } - - } -} diff --git a/AppNotifications/AppNotificationsImplementation.h b/AppNotifications/AppNotificationsImplementation.h deleted file mode 100644 index e54a180..0000000 --- a/AppNotifications/AppNotificationsImplementation.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "UtilsController.h" -#include "ContextUtils.h" -#include "UtilsCallsign.h" - -namespace WPEFramework { -namespace Plugin { - class AppNotificationsImplementation : public Exchange::IAppNotifications, public Exchange::IConfiguration { - private: - class SubscriberMap { - public: - SubscriberMap(AppNotificationsImplementation& parent) : mParent(parent), - mSubscriberMutex(), - mSubscribers(), - mAppGateway(nullptr), - mInternalGatewayNotifier(nullptr){} - - ~SubscriberMap() { - // cleanup mutex and map - std::lock_guard lock(mSubscriberMutex); - mSubscribers.clear(); - if (mAppGateway != nullptr) { - mAppGateway->Release(); - mAppGateway = nullptr; - } - - if (mInternalGatewayNotifier != nullptr) { - mInternalGatewayNotifier->Release(); - mInternalGatewayNotifier = nullptr; - } - } - - void Add(const string& key, const Exchange::IAppNotifications::AppNotificationContext& context); - - void Remove(const string& key, const Exchange::IAppNotifications::AppNotificationContext& context); - - std::vector Get(const string& key) const; - - bool Exists(const string& key) const; - - // create a new method called EventUpdate which accepts the key and JsonObject parameters - // the method first checks if the given key is available in the mSubscribers uses the mSubscriberMutex lock - // after verifications it loops through the iterator of values for the given key - void EventUpdate(const string& key, const string& payloadStr, const string& appId ); - - // Create a method to check if the SubscriberMap - void Dispatch(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload); - - void DispatchToGateway(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload); - - void DispatchToLaunchDelegate(const Exchange::IAppNotifications::AppNotificationContext& context, const string& payload); - void CleanupNotifications(const uint32_t &connectionId, const string& origin); - private: - AppNotificationsImplementation& mParent; - mutable std::mutex mSubscriberMutex; - std::map> mSubscribers; - Exchange::IAppGatewayResponder *mAppGateway; - Exchange::IAppGatewayResponder *mInternalGatewayNotifier; - }; - - // Class to accept the module and event and subscribe to Thunder and use a handler - // to print the notifications dispatched from Thunder. - // Class will have options for: - // 1. Subscribe which accepts module event - // 2. Unsubscribe which accepts module and event - class ThunderSubscriptionManager { - public: - ThunderSubscriptionManager(AppNotificationsImplementation& parent) : mParent(parent) { - } - - ~ThunderSubscriptionManager(); - - void Subscribe(const string& module, const string& event); - - void Unsubscribe(const string& module, const string& event); - - bool HandleNotifier(const string& module, const string& event, const bool& listen); - - // Add a method to lock the mThunderSubscriberMutex mutex and add an entry to mRegisteredNotifications - void RegisterNotification(const string& module, const string& event); - - // Remove an entry from the mRegisteredNotifications - void UnregisterNotification(const string& module, const string& event); - - // check if a given string has an existing entry in mRegisteredNotifications - bool IsNotificationRegistered(const string& module, const string& notification) const; - - private: - - struct NotificationKey { - string module; - string event; - - bool operator==(const NotificationKey& other) const { - return (this->module == other.module) && (this->event == other.event); - } - }; - - AppNotificationsImplementation& mParent; - mutable std::mutex mThunderSubscriberMutex; - std::vector mRegisteredNotifications; - }; - - AppNotificationsImplementation(const AppNotificationsImplementation&) = delete; - AppNotificationsImplementation& operator=(const AppNotificationsImplementation&) = delete; - - public: - AppNotificationsImplementation(); - ~AppNotificationsImplementation(); - - BEGIN_INTERFACE_MAP(AppNotificationsImplementation) - INTERFACE_ENTRY(Exchange::IAppNotifications) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - // IAppNotifications interface - Core::hresult Subscribe(const Exchange::IAppNotifications::AppNotificationContext &context /* @in */, - bool listen /* @in */, - const string &module /* @in */, - const string &event /* @in */) override; - - Core::hresult Emit(const string &event /* @in */, - const string &payload /* @in @opaque */, - const string &appId /* @in */) override; - - Core::hresult Cleanup(const uint32_t connectionId /* @in */, const string &origin /* @in */) override; - - // IConfiguration interface - uint32_t Configure(PluginHost::IShell* shell); - - class EXTERNAL SubscriberJob : public Core::IDispatch - { - public: - SubscriberJob(AppNotificationsImplementation* delegate, const string& module, const string& event, const bool subscribe) - : mParent(*delegate), mEvent(event), mModule(module), mSubscribe(subscribe) {} - - SubscriberJob() = delete; - SubscriberJob(const SubscriberJob &) = delete; - SubscriberJob &operator=(const SubscriberJob &) = delete; - ~SubscriberJob() - { - } - - static Core::ProxyType Create(AppNotificationsImplementation *parent, - const string& module, const string& event, const bool subscribe) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, module, event, subscribe))); - } - - virtual void Dispatch() - { - if (mSubscribe) { - mParent.mThunderManager.Subscribe(mModule, mEvent); - } else { - mParent.mThunderManager.Unsubscribe(mModule, mEvent); - } - } - - private: - AppNotificationsImplementation &mParent; - string mEvent; - string mModule; - bool mSubscribe; - }; - - class EXTERNAL EmitJob : public Core::IDispatch - { - public: - EmitJob(AppNotificationsImplementation* delegate, const string& event, const string& payload, const string& appId) - : mParent(*delegate), mEvent(event), mPayload(payload), mAppId(appId) {} - - EmitJob() = delete; - EmitJob(const EmitJob &) = delete; - EmitJob &operator=(const EmitJob &) = delete; - ~EmitJob() - { - } - - static Core::ProxyType Create(AppNotificationsImplementation *parent, - const string& event, const string& payload, const string& appId) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, event, payload, appId))); - } - - virtual void Dispatch() - { - mParent.mSubMap.EventUpdate(mEvent, mPayload, mAppId); - } - - private: - AppNotificationsImplementation &mParent; - string mEvent; - string mPayload; - string mAppId; - }; - - class Emitter: public Exchange::IAppNotificationHandler::IEmitter { - private: - Emitter(const Emitter&) = delete; - Emitter& operator=(const Emitter&) = delete; - public: - Emitter(AppNotificationsImplementation& parent) : mParent(parent) {} - - virtual void Emit(const string &event /* @in */, - const string &payload /* @in @opaque */, - const string &appId /* @in */) override - { - LOGINFO("Emit [event= %s payload=%s appId=%s]", - event.c_str(), payload.c_str(), appId.c_str()); - Core::IWorkerPool::Instance().Submit(EmitJob::Create(&mParent, event, payload, appId)); - } - - BEGIN_INTERFACE_MAP(Emitter) - INTERFACE_ENTRY(Exchange::IAppNotificationHandler::IEmitter) - END_INTERFACE_MAP - - private: - AppNotificationsImplementation& mParent; - }; - - private: - PluginHost::IShell* mShell; - SubscriberMap mSubMap; - ThunderSubscriptionManager mThunderManager; - Core::Sink mEmitter; - }; -} -} diff --git a/AppNotifications/CMakeLists.txt b/AppNotifications/CMakeLists.txt deleted file mode 100644 index c39831b..0000000 --- a/AppNotifications/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME AppNotifications) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(VERSION_MAJOR 1) -set(VERSION_MINOR 0) -set(VERSION_PATCH 0) - -add_compile_definitions(APPNOTIFICATIONS_MAJOR_VERSION=${VERSION_MAJOR}) -add_compile_definitions(APPNOTIFICATIONS_MINOR_VERSION=${VERSION_MINOR}) -add_compile_definitions(APPNOTIFICATIONS_PATCH_VERSION=${VERSION_PATCH}) - -set(MODULE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) - -set(PLUGIN_APPNOTIFICATIONS_STARTUPORDER "" CACHE STRING "To configure startup order of AppNotifications plugin") -set(PLUGIN_APPNOTIFICATIONS_AUTOSTART "false" CACHE STRING "Automatically start AppNotifications plugin") - -message("Setup ${MODULE_NAME} v${MODULE_VERSION}") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - AppNotificationsImplementation.cpp - AppNotifications.cpp - Module.cpp) - - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -# To error any missing links -target_link_options(${MODULE_NAME} PRIVATE -Wl,-z,defs) -# To error any warnings -add_compile_options(-Wall -Werror) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/AppNotifications/Module.cpp b/AppNotifications/Module.cpp deleted file mode 100755 index 713d4b1..0000000 --- a/AppNotifications/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/AppNotifications/Module.h b/AppNotifications/Module.h deleted file mode 100755 index 3b56bb9..0000000 --- a/AppNotifications/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_AppNotifications -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/AppNotifications/tests/CurlCmds.md b/AppNotifications/tests/CurlCmds.md deleted file mode 100644 index c1dcbba..0000000 --- a/AppNotifications/tests/CurlCmds.md +++ /dev/null @@ -1,20 +0,0 @@ -# FbMetrics JSON-RPC cURL Commands - -## Controller: Activate / Deactivate org.rdk.FbMetrics - -### Activate -```bash -curl -d '{"jsonrpc": "2.0","id":122,"method":"Controller.1.activate","params":{"callsign":"org.rdk.AppNotifications"}}' http://127.0.0.1:9998/jsonrpc -``` - -### Deactivate -```bash -curl -d '{"jsonrpc": "2.0","id":122,"method":"Controller.1.deactivate","params":{"callsign":"org.rdk.AppNotifications"}}' http://127.0.0.1:9998/jsonrpc -``` - ---- - -## Action -```bash -curl -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"100","method":"org.rdk.AppNotifications.1.subscribe","params": {"context": { "requestId":0, "appId":"com.example.app", "connectionId":"someConnectionguid" },"listen": true,"module": "org.rdk.FbSettings.1", "event": "TextToSpeech.Enabled"}}}' http://127.0.0.1:9998/jsonrpc -``` \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e4521e2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +### Changelog + +All notable changes to this project will be documented in this file. Dates are displayed in UTC. + +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + +#### [1.0.0] diff --git a/CMakeLists.txt b/CMakeLists.txt index cde223e..3171475 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,6 @@ if(COMCAST_CONFIG) include(services.cmake) endif() -option(PLUGIN_OCICONTAINER "Include OCIContainer plugin" OFF) - # Library installation section string(TOLOWER ${NAMESPACE} STORAGE_DIRECTORY) @@ -56,123 +54,7 @@ if(DISABLE_SECURITY_TOKEN) endif() if(PLUGIN_USERSETTINGS) - add_subdirectory(UserSettings) -endif() - -if(PLUGIN_USB_MASS_STORAGE) - add_subdirectory(USBMassStorage) -endif() - -if(PLUGIN_OCICONTAINER) - add_subdirectory(OCIContainer) -endif() - -if(PLUGIN_PERSISTENTSTORE) - add_subdirectory(PersistentStore) -endif() - -if(PLUGIN_USBDEVICE) - add_subdirectory(USBDevice) -endif() - -if(PLUGIN_TELEMETRY) - add_subdirectory(Telemetry) -endif() - -if(PLUGIN_MONITOR) - add_subdirectory(Monitor) -endif() - -if(PLUGIN_RDKSHELL) - add_subdirectory(RDKShell) -endif() - -if(PLUGIN_RUSTADAPTER) - add_subdirectory(RustAdapter) -endif() - -if(PLUGIN_MESSAGECONTROL) - add_subdirectory(MessageControl) -endif() - -if (PLUGIN_RESOURCEMANAGER) - add_subdirectory(ResourceManager) -endif() - -if (PLUGIN_ANALYTICS) - add_subdirectory(Analytics) -endif() - -if(PLUGIN_RDK_WINDOW_MANAGER) - add_subdirectory(RDKWindowManager) -endif() - -if(PLUGIN_CLOUDSTORE) - add_subdirectory(CloudStore) -endif() - -if(PLUGIN_SHAREDSTORAGE) - add_subdirectory(SharedStorage) -endif() - -if(PLUGIN_WEBBRIDGE) - add_subdirectory(WebBridge) -endif() - -if(PLUGIN_LIFECYCLE_MANAGER) - add_subdirectory(LifecycleManager) -endif() - -if(PLUGIN_APPMANAGER) - add_subdirectory(AppManager) -endif() - -if(PLUGIN_RUNTIME_MANAGER) - add_subdirectory(RuntimeManager) -endif() - -if(PLUGIN_STORAGE_MANAGER) - add_subdirectory(StorageManager) -endif() - -if(PLUGIN_PACKAGE_MANAGER) - add_subdirectory(PackageManager) -endif() - -if(PLUGIN_DOWNLOADMANAGER) - add_subdirectory(DownloadManager) -endif() - -if(PLUGIN_NATIVEJS) - add_subdirectory(NativeJS) -endif() - -if(PLUGIN_SCENESET) - add_subdirectory(SceneSet) -endif() - -if(PLUGIN_TELEMETRYMETRICS) - add_subdirectory(TelemetryMetrics) -endif() - -if(PLUGIN_PREINSTALL_MANAGER) - add_subdirectory(PreinstallManager) -endif() - -if(PLUGIN_MIGRATION) - add_subdirectory(Migration) -endif() - -if(PLUGIN_APPGATEWAY) - add_subdirectory(AppGateway) -endif() - -if(PLUGIN_APPNOTIFICATIONS) - add_subdirectory(AppNotifications) -endif() - -if(PLUGIN_FBSETTINGS) - add_subdirectory(FbSettings) + add_subdirectory(plugin) endif() diff --git a/CloudStore/CHANGELOG.md b/CloudStore/CHANGELOG.md deleted file mode 100644 index 8842937..0000000 --- a/CloudStore/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. diff --git a/CloudStore/CMakeLists.txt b/CloudStore/CMakeLists.txt deleted file mode 100644 index 7305579..0000000 --- a/CloudStore/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -set(PLUGIN_NAME CloudStore) -find_package(WPEFramework NAMES WPEFramework Thunder) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(CMAKE_CXX_STANDARD 11) - -set(PLUGIN_CLOUDSTORE_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_CLOUDSTORE_URI "" CACHE STRING "Endpoint") -set(PLUGIN_CLOUDSTORE_STARTUPORDER "" CACHE STRING "To configure startup order of the plugin") - -add_library(${MODULE_NAME} SHARED - CloudStore.cpp - Module.cpp -) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -target_link_libraries(${MODULE_NAME} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -find_library(RFC_LIBRARIES NAMES rfcapi) -if (RFC_LIBRARIES) - find_path(RFC_INCLUDE_DIRS NAMES rfcapi.h REQUIRED) - target_include_directories(${MODULE_NAME} PRIVATE ${RFC_INCLUDE_DIRS}) - target_link_libraries(${MODULE_NAME} PRIVATE ${RFC_LIBRARIES}) - target_compile_definitions(${MODULE_NAME} PRIVATE WITH_RFC) -endif () - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) -add_library(${PLUGIN_IMPLEMENTATION} SHARED - Module.cpp - CloudStoreImplementation.cpp -) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -find_library(IARMBUS_LIBRARIES NAMES IARMBus) -if (IARMBUS_LIBRARIES) - find_path(IARMBUS_INCLUDE_DIRS NAMES libIBus.h PATH_SUFFIXES rdk/iarmbus REQUIRED) - find_path(IARMSYS_INCLUDE_DIRS NAMES sysMgr.h PATH_SUFFIXES rdk/iarmmgrs/sysmgr REQUIRED) - target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS} ${IARMSYS_INCLUDE_DIRS}) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_LIBRARIES}) - target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE WITH_SYSMGR) -endif () - -if(NOT RDK_SERVICE_L2_TEST) - find_package(Protobuf REQUIRED) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${Protobuf_LIBRARIES}) - - add_custom_target(protoc - ${Protobuf_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto - ) - add_dependencies(${PLUGIN_IMPLEMENTATION} protoc) - - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE grpc++) - find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) - - add_custom_target(protoc-gen-grpc - ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto - ) - add_dependencies(${PLUGIN_IMPLEMENTATION} protoc-gen-grpc) - - set(PROTO_SRCS secure_storage.pb.cc secure_storage.grpc.pb.cc) - target_sources(${PLUGIN_IMPLEMENTATION} PRIVATE ${PROTO_SRCS}) - set_property(SOURCE ${PROTO_SRCS} PROPERTY GENERATED 1) - target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -endif() - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/CloudStore/CloudStore.conf.in b/CloudStore/CloudStore.conf.in deleted file mode 100644 index 7c33ccf..0000000 --- a/CloudStore/CloudStore.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.CloudStore" -startuporder = "@PLUGIN_CLOUDSTORE_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_CLOUDSTORE_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) - -configuration.add("uri", "@PLUGIN_CLOUDSTORE_URI@") diff --git a/CloudStore/CloudStore.config b/CloudStore/CloudStore.config deleted file mode 100644 index ca02d98..0000000 --- a/CloudStore/CloudStore.config +++ /dev/null @@ -1,17 +0,0 @@ -set(autostart true) -set(preconditions Platform) -set(callsign "org.rdk.CloudStore") - -if(PLUGIN_CLOUDSTORE_STARTUPORDER) -set (startuporder ${PLUGIN_CLOUDSTORE_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_CLOUDSTORE_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() - kv(uri ${PLUGIN_CLOUDSTORE_URI}) -end() -ans(configuration) diff --git a/CloudStore/CloudStore.cpp b/CloudStore/CloudStore.cpp deleted file mode 100644 index b8fc2bb..0000000 --- a/CloudStore/CloudStore.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CloudStore.h" -#ifdef WITH_RFC -#include "rfcapi.h" -#endif - -#include - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 1 - -namespace WPEFramework { - -namespace Plugin { - - namespace { - - static Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {}); - } - - SERVICE_REGISTRATION(CloudStore, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - const string CloudStore::Initialize(PluginHost::IShell* service) - { - string result; - - ASSERT(service != nullptr); - ASSERT(_store2 == nullptr); - ASSERT(_service == nullptr); - ASSERT(_connectionId == 0); - - SYSLOG(Logging::Startup, (_T("CloudStore::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - - auto configLine = _service->ConfigLine(); - _config.FromString(configLine); - - auto uri = _config.Uri.Value(); - -#ifdef WITH_RFC - RFC_ParamData_t rfcParam; - auto rfcStatus = getRFCParameter(nullptr, URI_RFC, &rfcParam); - if (rfcStatus == WDMP_SUCCESS) { - if (rfcParam.value[0]) { - uri = rfcParam.value; - } - } else { - TRACE(Trace::Error, (_T("%s rfc error %d"), __FUNCTION__, rfcStatus)); - } -#endif - - Core::SystemInfo::SetEnvironment(URI_ENV, uri); - - SYSLOG(Logging::Startup, (_T("grpc endpoint is %s"), uri.c_str())); - - string token; - auto security = _service->QueryInterfaceByCallsign< - PluginHost::IAuthenticate>("SecurityAgent"); - if (security != nullptr) { - string payload = "http://localhost"; - auto ret = security->CreateToken( - static_cast(payload.length()), - reinterpret_cast(payload.c_str()), - token); - if (ret != Core::ERROR_NONE) { - SYSLOG(Logging::Startup, - (_T("Couldn't create token: %d"), ret)); - } - security->Release(); - } - - Core::SystemInfo::SetEnvironment(TOKEN_ENV, token); - - _service->Register(&_notification); - - _store2 = _service->Root(_connectionId, RPC::CommunicationTimeOut, _T("CloudStoreImplementation")); - if (_store2 != nullptr) { - - auto configConnection = _store2->QueryInterface(); - if (configConnection != nullptr) { - configConnection->Configure(service); - configConnection->Release(); - } else { - result = _T("Failed to get IConfiguration"); - } - - Exchange::JStore2::Register(*this, _store2); - _store2->Register(&_store2Sink); - } else { - result = _T("Couldn't create implementation instance"); - } - - return result; - } - - void CloudStore::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("CloudStore::Deinitialize")))); - - _service->Unregister(&_notification); - - if (_store2 != nullptr) { - _store2->Unregister(&_store2Sink); - Exchange::JStore2::Unregister(*this); - - auto connection = _service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED auto result = _store2->Release(); - _store2 = nullptr; - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if (connection != nullptr) { - connection->Terminate(); - connection->Release(); - } - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("CloudStore de-initialised")))); - } - - string CloudStore::Information() const - { - return (string()); - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/CloudStore/CloudStore.h b/CloudStore/CloudStore.h deleted file mode 100644 index 9c4bceb..0000000 --- a/CloudStore/CloudStore.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include - -namespace WPEFramework { -namespace Plugin { - - class CloudStore : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - class Config : public Core::JSON::Container { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - public: - Config() - : Core::JSON::Container() - { - Add(_T("uri"), &Uri); - } - - public: - Core::JSON::String Uri; - }; - - class Store2Notification : public Exchange::IStore2::INotification { - private: - Store2Notification(const Store2Notification&) = delete; - Store2Notification& operator=(const Store2Notification&) = delete; - - public: - explicit Store2Notification(CloudStore& parent) - : _parent(parent) - { - } - ~Store2Notification() override = default; - - public: - void ValueChanged(const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value) override - { - Exchange::JStore2::Event::ValueChanged(_parent, scope, ns, key, value); - } - - BEGIN_INTERFACE_MAP(Store2Notification) - INTERFACE_ENTRY(Exchange::IStore2::INotification) - END_INTERFACE_MAP - - private: - CloudStore& _parent; - }; - - class RemoteConnectionNotification : public RPC::IRemoteConnection::INotification { - private: - RemoteConnectionNotification() = delete; - RemoteConnectionNotification(const RemoteConnectionNotification&) = delete; - RemoteConnectionNotification& operator=(const RemoteConnectionNotification&) = delete; - - public: - explicit RemoteConnectionNotification(CloudStore& parent) - : _parent(parent) - { - } - ~RemoteConnectionNotification() override = default; - - BEGIN_INTERFACE_MAP(RemoteConnectionNotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - } - void Deactivated(RPC::IRemoteConnection* connection) override - { - if (connection->Id() == _parent._connectionId) { - ASSERT(_parent._service != nullptr); - Core::IWorkerPool::Instance().Schedule( - Core::Time::Now(), - PluginHost::IShell::Job::Create( - _parent._service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - private: - CloudStore& _parent; - }; - - private: - CloudStore(const CloudStore&) = delete; - CloudStore& operator=(const CloudStore&) = delete; - - public: - CloudStore() - : PluginHost::JSONRPC() - , _service(nullptr) - , _connectionId(0) - , _store2(nullptr) - , _store2Sink(*this) - , _notification(*this) - { - } - ~CloudStore() override = default; - - BEGIN_INTERFACE_MAP(CloudStore) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IStore2, _store2) - END_INTERFACE_MAP - - public: - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - Config _config; - PluginHost::IShell* _service; - uint32_t _connectionId; - Exchange::IStore2* _store2; - Core::Sink _store2Sink; - Core::Sink _notification; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/CloudStore/CloudStoreImplementation.cpp b/CloudStore/CloudStoreImplementation.cpp deleted file mode 100644 index 2a357c5..0000000 --- a/CloudStore/CloudStoreImplementation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CloudStoreImplementation.h" -#include "grpc/Store2.h" - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(CloudStoreImplementation, 1, 0); - - CloudStoreImplementation::CloudStoreImplementation() - : _accountStore2(Core::Service::Create()) - { - } - - CloudStoreImplementation::~CloudStoreImplementation() - { - if (_accountStore2 != nullptr) { - _accountStore2->Release(); - _accountStore2 = nullptr; - } - } - - uint32_t CloudStoreImplementation::Configure(PluginHost::IShell* service) - { - ASSERT(_accountStore2 != nullptr); - - auto configConnection = _accountStore2->QueryInterface(); - if (configConnection != nullptr) { - configConnection->Configure(service); - configConnection->Release(); - } - - return Core::ERROR_NONE; - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/CloudStore/CloudStoreImplementation.h b/CloudStore/CloudStoreImplementation.h deleted file mode 100644 index 7a5c0fb..0000000 --- a/CloudStore/CloudStoreImplementation.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class CloudStoreImplementation : public Exchange::IStore2, public Exchange::IConfiguration { - private: - CloudStoreImplementation(const CloudStoreImplementation&) = delete; - CloudStoreImplementation& operator=(const CloudStoreImplementation&) = delete; - - public: - CloudStoreImplementation(); - ~CloudStoreImplementation() override; - - virtual uint32_t Configure(PluginHost::IShell* service) override; - - BEGIN_INTERFACE_MAP(CloudStoreImplementation) - INTERFACE_ENTRY(IStore2) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - private: - uint32_t Register(IStore2::INotification* notification) override - { - if (_accountStore2 != nullptr) { - _accountStore2->Register(notification); - } - return Core::ERROR_NONE; - } - uint32_t Unregister(IStore2::INotification* notification) override - { - if (_accountStore2 != nullptr) { - _accountStore2->Unregister(notification); - } - return Core::ERROR_NONE; - } - uint32_t SetValue(const IStore2::ScopeType, const string& ns, const string& key, const string& value, const uint32_t ttl) override - { - if (_accountStore2 != nullptr) { - return _accountStore2->SetValue(IStore2::ScopeType::ACCOUNT, ns, key, value, ttl); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetValue(const IStore2::ScopeType, const string& ns, const string& key, string& value, uint32_t& ttl) override - { - if (_accountStore2 != nullptr) { - return _accountStore2->GetValue(IStore2::ScopeType::ACCOUNT, ns, key, value, ttl); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t DeleteKey(const IStore2::ScopeType, const string& ns, const string& key) override - { - if (_accountStore2 != nullptr) { - return _accountStore2->DeleteKey(IStore2::ScopeType::ACCOUNT, ns, key); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t DeleteNamespace(const IStore2::ScopeType, const string& ns) override - { - if (_accountStore2 != nullptr) { - return _accountStore2->DeleteNamespace(IStore2::ScopeType::ACCOUNT, ns); - } - return Core::ERROR_NOT_SUPPORTED; - } - - private: - IStore2* _accountStore2; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/CloudStore/Module.cpp b/CloudStore/Module.cpp deleted file mode 100644 index f3869fc..0000000 --- a/CloudStore/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/CloudStore/Module.h b/CloudStore/Module.h deleted file mode 100644 index 6dccbcf..0000000 --- a/CloudStore/Module.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_CloudStore -#endif - -#include - -#define URI_ENV "CLOUDSTORE_URI" -#define TOKEN_ENV "CLOUDSTORE_TOKEN" -#define IARM_INIT_NAME "Thunder_Plugins" -#define URI_RFC "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.CloudStore.Uri" -#define PARTNER_ID_FILENAME "/opt/www/authService/partnerId3.dat" -#define ACCOUNT_ID_FILENAME "/opt/www/authService/said.dat" -#define DEVICE_ID_FILENAME "/opt/www/authService/xdeviceid.dat" -#define IARM_TIMEOUT 1000 -#define JSON_RPC_TIMEOUT 2000 -#define GRPC_TIMEOUT 3000 -#define IDLE_TIMEOUT 30000 - -#undef EXTERNAL -#define EXTERNAL diff --git a/CloudStore/grpc/Store2.h b/CloudStore/grpc/Store2.h deleted file mode 100644 index d810918..0000000 --- a/CloudStore/grpc/Store2.h +++ /dev/null @@ -1,434 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../Module.h" -#include "secure_storage.grpc.pb.h" -#include -#include -#include -#include -#include -#ifdef WITH_SYSMGR -#include -#include -#endif - -namespace WPEFramework { -namespace Plugin { - namespace Grpc { - - class Store2 : public Exchange::IStore2, public Exchange::IConfiguration { - private: - class Job : public Core::IDispatch { - public: - Job(Store2* parent, const ScopeType scope, const string& ns, const string& key, const string& value) - : _parent(parent) - , _scope(scope) - , _ns(ns) - , _key(key) - , _value(value) - { - _parent->AddRef(); - } - ~Job() override - { - _parent->Release(); - } - void Dispatch() override - { - _parent->OnValueChanged(_scope, _ns, _key, _value); - } - - private: - Store2* _parent; - const ScopeType _scope; - const string _ns; - const string _key; - const string _value; - }; - - private: - Store2(const Store2&) = delete; - Store2& operator=(const Store2&) = delete; - - public: - Store2() - : Store2(getenv(URI_ENV), getenv(TOKEN_ENV)) - { - } - Store2(const string& uri, const string& token) - : IStore2() - , _uri(uri) - , _token(token) - , _service(nullptr) - , _authorization((_uri.find("localhost") == string::npos) && (_uri.find("0.0.0.0") == string::npos)) - { - Open(); - } - - ~Store2() override - { - if (_service != nullptr) { - _service->Release(); - _service = nullptr; - } - } - - private: - void Open() - { - grpc::ChannelArguments args; - args.SetInt(GRPC_ARG_CLIENT_IDLE_TIMEOUT_MS, IDLE_TIMEOUT); - std::shared_ptr creds; - if (_authorization) { - creds = grpc::SslCredentials(grpc::SslCredentialsOptions()); - } else { - creds = grpc::InsecureChannelCredentials(); - } - _stub = ::distp::gateway::secure_storage::v1::SecureStorageService::NewStub( - grpc::CreateCustomChannel(_uri, creds, args)); - } - - private: - bool IsTimeSynced() const - { -#ifdef WITH_SYSMGR - // Get actual state, as it may change at any time... - IARM_Bus_Init(IARM_INIT_NAME); - IARM_Bus_Connect(); - IARM_Bus_SYSMgr_GetSystemStates_Param_t param; - if ((IARM_Bus_Call_with_IPCTimeout( - IARM_BUS_SYSMGR_NAME, - IARM_BUS_SYSMGR_API_GetSystemStates, - ¶m, - sizeof(param), - IARM_TIMEOUT) // Timeout - != IARM_RESULT_SUCCESS) - || !param.time_source.state) { - return false; - } -#endif - return true; - } - string GetToken() const - { - if (_service == nullptr) - { - TRACE(Trace::Error, (_T("No IShell"))); - return ""; - } - - // Get actual token, as it may change at any time... - Exchange::IAuthService *authservicePlugin = _service->QueryInterfaceByCallsign("org.rdk.AuthService"); - if (authservicePlugin != nullptr) { - WPEFramework::Exchange::IAuthService::GetServiceAccessTokenResult atRes; - uint32_t res = authservicePlugin->GetServiceAccessToken(atRes); - authservicePlugin->Release(); - - if (res == Core::ERROR_NONE) - return atRes.token; - } - else - TRACE(Trace::Error, (_T("Failed to get IAuthService"))); - - return ""; - } - string GetPartnerId() const - { - // Get actual id, as it may change at any time... - std::ifstream input(PARTNER_ID_FILENAME); - string line = ""; - getline(input, line); - return line; - } - string GetAccountId() const - { - // Get actual id, as it may change at any time... - std::ifstream input(ACCOUNT_ID_FILENAME); - string line = ""; - getline(input, line); - return line; - } - string GetDeviceId() const - { - // Get actual id, as it may change at any time... - std::ifstream input(DEVICE_ID_FILENAME); - string line = ""; - getline(input, line); - return line; - } - - public: - uint32_t Register(INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - ASSERT(std::find(_clients.begin(), _clients.end(), notification) == _clients.end()); - - notification->AddRef(); - _clients.push_back(notification); - - return Core::ERROR_NONE; - } - uint32_t Unregister(INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - std::list::iterator - index(std::find(_clients.begin(), _clients.end(), notification)); - - ASSERT(index != _clients.end()); - - if (index != _clients.end()) { - notification->Release(); - _clients.erase(index); - } - - return Core::ERROR_NONE; - } - - uint32_t SetValue(const ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) override - { - uint32_t result; - - grpc::ClientContext context; - if (_authorization) { - context.AddMetadata("authorization", "Bearer " + GetToken()); - } - - context.set_deadline(std::chrono::system_clock::now() + std::chrono::milliseconds(GRPC_TIMEOUT)); // Timeout - ::distp::gateway::secure_storage::v1::UpdateValueRequest request; - request.set_partner_id(GetPartnerId()); - request.set_account_id(GetAccountId()); - request.set_device_id(GetDeviceId()); - auto v = new ::distp::gateway::secure_storage::v1::Value(); - v->set_value(value); - if (ttl != 0) { - auto t = new google::protobuf::Duration(); - t->set_seconds(ttl); - v->set_allocated_ttl(t); - } - auto k = new ::distp::gateway::secure_storage::v1::Key(); - k->set_app_id(ns); - k->set_key(key); - k->set_scope(scope == ScopeType::ACCOUNT - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT - : (scope == ScopeType::DEVICE - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_DEVICE - : ::distp::gateway::secure_storage::v1::Scope::SCOPE_UNSPECIFIED)); - v->set_allocated_key(k); - request.set_allocated_value(v); - ::distp::gateway::secure_storage::v1::UpdateValueResponse response; - auto status = _stub->UpdateValue(&context, request, &response); - - if (status.ok()) { - Core::IWorkerPool::Instance().Submit(Core::ProxyType( - Core::ProxyType::Create(this, scope, ns, key, value))); // Decouple notification - - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, status); - if (status.error_code() == grpc::StatusCode::INVALID_ARGUMENT) { - result = Core::ERROR_INVALID_INPUT_LENGTH; - } else { - result = Core::ERROR_GENERAL; - } - } - - return result; - } - uint32_t GetValue(const ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) override - { - uint32_t result; - - grpc::ClientContext context; - if (_authorization) { - context.AddMetadata("authorization", "Bearer " + GetToken()); - } - context.set_deadline(std::chrono::system_clock::now() + std::chrono::milliseconds(GRPC_TIMEOUT)); // Timeout - ::distp::gateway::secure_storage::v1::GetValueRequest request; - request.set_partner_id(GetPartnerId()); - request.set_account_id(GetAccountId()); - request.set_device_id(GetDeviceId()); - auto k = new ::distp::gateway::secure_storage::v1::Key(); - k->set_app_id(ns); - k->set_key(key); - k->set_scope(scope == ScopeType::ACCOUNT - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT - : (scope == ScopeType::DEVICE - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_DEVICE - : ::distp::gateway::secure_storage::v1::Scope::SCOPE_UNSPECIFIED)); - request.set_allocated_key(k); - ::distp::gateway::secure_storage::v1::GetValueResponse response; - auto status = _stub->GetValue(&context, request, &response); - - if (status.ok()) { - if (response.has_value()) { - auto v = response.value(); - if (v.has_ttl()) { - ttl = v.ttl().seconds(); - value = v.value(); - result = Core::ERROR_NONE; - } else if (v.has_expire_time() && (v.expire_time().seconds() != 0)) { - if (IsTimeSynced()) { - ttl = v.expire_time().seconds() - time(nullptr); - value = v.value(); - result = Core::ERROR_NONE; - } else { - result = Core::ERROR_PENDING_CONDITIONS; - } - } else { - ttl = 0; - value = v.value(); - result = Core::ERROR_NONE; - } - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - OnError(__FUNCTION__, status); - if (status.error_code() == grpc::StatusCode::INVALID_ARGUMENT) { - result = Core::ERROR_INVALID_INPUT_LENGTH; - } else if (status.error_code() == grpc::StatusCode::NOT_FOUND) { - result = Core::ERROR_UNKNOWN_KEY; - } else { - result = Core::ERROR_GENERAL; - } - } - - return result; - } - uint32_t DeleteKey(const ScopeType scope, const string& ns, const string& key) override - { - uint32_t result; - - grpc::ClientContext context; - if (_authorization) { - context.AddMetadata("authorization", "Bearer " + GetToken()); - } - context.set_deadline(std::chrono::system_clock::now() + std::chrono::milliseconds(GRPC_TIMEOUT)); // Timeout - ::distp::gateway::secure_storage::v1::DeleteValueRequest request; - request.set_partner_id(GetPartnerId()); - request.set_account_id(GetAccountId()); - request.set_device_id(GetDeviceId()); - auto k = new ::distp::gateway::secure_storage::v1::Key(); - k->set_app_id(ns); - k->set_key(key); - k->set_scope(scope == ScopeType::ACCOUNT - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT - : (scope == ScopeType::DEVICE - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_DEVICE - : ::distp::gateway::secure_storage::v1::Scope::SCOPE_UNSPECIFIED)); - request.set_allocated_key(k); - ::distp::gateway::secure_storage::v1::DeleteValueResponse response; - auto status = _stub->DeleteValue(&context, request, &response); - - if (status.ok()) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, status); - if (status.error_code() == grpc::StatusCode::INVALID_ARGUMENT) { - result = Core::ERROR_INVALID_INPUT_LENGTH; - } else { - result = Core::ERROR_GENERAL; - } - } - - return result; - } - uint32_t DeleteNamespace(const ScopeType scope, const string& ns) override - { - uint32_t result; - - grpc::ClientContext context; - if (_authorization) { - context.AddMetadata("authorization", "Bearer " + GetToken()); - } - context.set_deadline(std::chrono::system_clock::now() + std::chrono::milliseconds(GRPC_TIMEOUT)); // Timeout - ::distp::gateway::secure_storage::v1::DeleteAllValuesRequest request; - request.set_partner_id(GetPartnerId()); - request.set_account_id(GetAccountId()); - request.set_device_id(GetDeviceId()); - request.set_app_id(ns); - request.set_scope(scope == ScopeType::ACCOUNT - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT - : (scope == ScopeType::DEVICE - ? ::distp::gateway::secure_storage::v1::Scope::SCOPE_DEVICE - : ::distp::gateway::secure_storage::v1::Scope::SCOPE_UNSPECIFIED)); - ::distp::gateway::secure_storage::v1::DeleteAllValuesResponse response; - auto status = _stub->DeleteAllValues(&context, request, &response); - - if (status.ok()) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, status); - result = Core::ERROR_GENERAL; - } - - return result; - } - - virtual uint32_t Configure(PluginHost::IShell* service) override - { - ASSERT(service != nullptr); - _service = service; - _service->AddRef(); - - return Core::ERROR_NONE; - } - - BEGIN_INTERFACE_MAP(Store2) - INTERFACE_ENTRY(IStore2) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - private: - void OnValueChanged(const ScopeType scope, const string& ns, const string& key, const string& value) - { - Core::SafeSyncType lock(_clientLock); - - std::list::iterator - index(_clients.begin()); - - while (index != _clients.end()) { - // If main process is out of threads, this can time out, and IPC will mess up... - (*index)->ValueChanged(scope, ns, key, value); - index++; - } - } - void OnError(const char* fn, const grpc::Status& status) const - { - TRACE(Trace::Error, (_T("%s grpc error %d %s %s"), fn, status.error_code(), status.error_message().c_str(), status.error_details().c_str())); - } - - private: - const string _uri; - const string _token; - PluginHost::IShell* _service; - const bool _authorization; - std::unique_ptr<::distp::gateway::secure_storage::v1::SecureStorageService::Stub> _stub; - std::list _clients; - Core::CriticalSection _clientLock; - }; - - } // namespace Grpc -} // namespace Plugin -} // namespace WPEFramework diff --git a/CloudStore/grpc/l0test/CMakeLists.txt b/CloudStore/grpc/l0test/CMakeLists.txt deleted file mode 100644 index 4f0b61c..0000000 --- a/CloudStore/grpc/l0test/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -project(grpcl0test) - -set(CMAKE_CXX_STANDARD 11) - -add_executable(${PROJECT_NAME} - ../../Module.cpp - Store2Test.cpp -) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) -FetchContent_MakeAvailable(googletest) -target_link_libraries(${PROJECT_NAME} PRIVATE gmock_main) - -find_package(WPEFramework NAMES WPEFramework Thunder) -find_package(${NAMESPACE}Plugins REQUIRED) -target_link_libraries(${PROJECT_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -find_package(Protobuf REQUIRED) -target_link_libraries(${PROJECT_NAME} PRIVATE ${Protobuf_LIBRARIES}) - -add_custom_target(protoc - ${Protobuf_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto -) -add_dependencies(${PROJECT_NAME} protoc) - -target_link_libraries(${PROJECT_NAME} PRIVATE grpc++) -find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) - -add_custom_target(protoc-gen-grpc - ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto -) -add_dependencies(${PROJECT_NAME} protoc-gen-grpc) - -set(PROTO_SRCS secure_storage.pb.cc secure_storage.grpc.pb.cc) -target_sources(${PROJECT_NAME} PRIVATE ${PROTO_SRCS}) -set_property(SOURCE ${PROTO_SRCS} PROPERTY GENERATED 1) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/CloudStore/grpc/l0test/SecureStorageServiceMock.h b/CloudStore/grpc/l0test/SecureStorageServiceMock.h deleted file mode 100644 index 11064f6..0000000 --- a/CloudStore/grpc/l0test/SecureStorageServiceMock.h +++ /dev/null @@ -1,33 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "secure_storage.grpc.pb.h" -#include - -class SecureStorageServiceMock : public ::distp::gateway::secure_storage::v1::SecureStorageService::Service { -public: - ~SecureStorageServiceMock() override = default; - MOCK_METHOD(::grpc::Status, GetValue, (::grpc::ServerContext * context, const ::distp::gateway::secure_storage::v1::GetValueRequest* request, ::distp::gateway::secure_storage::v1::GetValueResponse* response), (override)); - MOCK_METHOD(::grpc::Status, UpdateValue, (::grpc::ServerContext * context, const ::distp::gateway::secure_storage::v1::UpdateValueRequest* request, ::distp::gateway::secure_storage::v1::UpdateValueResponse* response), (override)); - MOCK_METHOD(::grpc::Status, DeleteValue, (::grpc::ServerContext * context, const ::distp::gateway::secure_storage::v1::DeleteValueRequest* request, ::distp::gateway::secure_storage::v1::DeleteValueResponse* response), (override)); - MOCK_METHOD(::grpc::Status, DeleteAllValues, (::grpc::ServerContext * context, const ::distp::gateway::secure_storage::v1::DeleteAllValuesRequest* request, ::distp::gateway::secure_storage::v1::DeleteAllValuesResponse* response), (override)); - MOCK_METHOD(::grpc::Status, SeedValue, (::grpc::ServerContext * context, const ::distp::gateway::secure_storage::v1::SeedValueRequest* request, ::distp::gateway::secure_storage::v1::SeedValueResponse* response), (override)); -}; diff --git a/CloudStore/grpc/l0test/Server.h b/CloudStore/grpc/l0test/Server.h deleted file mode 100644 index 4593020..0000000 --- a/CloudStore/grpc/l0test/Server.h +++ /dev/null @@ -1,39 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include - -struct Server { - std::unique_ptr server; - Server(const std::string& uri, grpc::Service* service) - { - grpc::ServerBuilder builder; - builder.AddListeningPort(uri, grpc::InsecureServerCredentials()); - builder.RegisterService(service); - server = builder.BuildAndStart(); - } - ~Server() - { - server->Shutdown(); - } -}; diff --git a/CloudStore/grpc/l0test/Store2Test.cpp b/CloudStore/grpc/l0test/Store2Test.cpp deleted file mode 100644 index 14f04a6..0000000 --- a/CloudStore/grpc/l0test/Store2Test.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include - -#include "../Store2.h" -#include "SecureStorageServiceMock.h" -#include "Server.h" -#include "WorkerPoolImplementation.h" - -using ::distp::gateway::secure_storage::v1::DeleteAllValuesRequest; -using ::distp::gateway::secure_storage::v1::DeleteAllValuesResponse; -using ::distp::gateway::secure_storage::v1::DeleteValueRequest; -using ::distp::gateway::secure_storage::v1::DeleteValueResponse; -using ::distp::gateway::secure_storage::v1::GetValueRequest; -using ::distp::gateway::secure_storage::v1::GetValueResponse; -using ::distp::gateway::secure_storage::v1::Key; -using ::distp::gateway::secure_storage::v1::Scope; -using ::distp::gateway::secure_storage::v1::UpdateValueRequest; -using ::distp::gateway::secure_storage::v1::UpdateValueResponse; -using ::distp::gateway::secure_storage::v1::Value; -using ::testing::_; -using ::testing::Eq; -using ::testing::Gt; -using ::testing::Invoke; -using ::testing::IsFalse; -using ::testing::IsTrue; -using ::testing::Le; -using ::testing::NiceMock; -using ::testing::Return; -using ::testing::Test; -using ::WPEFramework::Core::Time; -using ::WPEFramework::Exchange::IStore2; -using ::WPEFramework::Plugin::Grpc::Store2; - -const auto kUri = "0.0.0.0:50051"; -const auto kValue = "value_1"; -const auto kKey = "key_1"; -const auto kAppId = "app_id_1"; -const auto kTtl = 100; -const auto kScope = Scope::SCOPE_ACCOUNT; - -class AStore2 : public Test { -protected: - WPEFramework::Core::ProxyType workerPool; - NiceMock service; - Server server; - WPEFramework::Core::ProxyType store2; - AStore2() - : workerPool(WPEFramework::Core::ProxyType::Create( - WPEFramework::Core::Thread::DefaultStackSize())) - , server(kUri, &service) - , store2(WPEFramework::Core::ProxyType::Create(kUri, "")) - { - WPEFramework::Core::IWorkerPool::Assign(&(*workerPool)); - } - ~AStore2() override - { - WPEFramework::Core::IWorkerPool::Assign(nullptr); - } -}; - -TEST_F(AStore2, GetsValueWithTtl) -{ - GetValueRequest req; - ON_CALL(service, GetValue(_, _, _)) - .WillByDefault(Invoke( - [&](::grpc::ServerContext*, const GetValueRequest* request, GetValueResponse* response) { - req = (*request); - auto v = new Value(); - v->set_value(kValue); - auto t = new google::protobuf::Duration(); - t->set_seconds(kTtl); - v->set_allocated_ttl(t); - auto k = new Key(); - k->set_key(request->key().key()); - k->set_app_id(request->key().app_id()); - k->set_scope(request->key().scope()); - v->set_allocated_key(k); - response->set_allocated_value(v); - return grpc::Status::OK; - })); - - string v; - uint32_t t; - ASSERT_THAT(store2->GetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, v, t), Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(req.has_key(), IsTrue()); - EXPECT_THAT(req.key().key(), Eq(kKey)); - EXPECT_THAT(req.key().app_id(), Eq(kAppId)); - EXPECT_THAT(req.key().scope(), Eq(kScope)); - EXPECT_THAT(v, Eq(kValue)); - EXPECT_THAT(t, Eq(kTtl)); -} - -TEST_F(AStore2, DoesNotGetValueWhenResponseHasNoValue) -{ - ON_CALL(service, GetValue(_, _, _)) - .WillByDefault(Return(grpc::Status(grpc::StatusCode::OK, ""))); - - string v; - uint32_t t; - EXPECT_THAT(store2->GetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, v, t), Eq(WPEFramework::Core::ERROR_UNKNOWN_KEY)); -} - -TEST_F(AStore2, DoesNotGetValueWhenNOT_FOUND) -{ - ON_CALL(service, GetValue(_, _, _)) - .WillByDefault(Return(grpc::Status(grpc::StatusCode::NOT_FOUND, ""))); - - string v; - uint32_t t; - EXPECT_THAT(store2->GetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, v, t), Eq(WPEFramework::Core::ERROR_UNKNOWN_KEY)); -} - -TEST_F(AStore2, DoesNotGetValueWhenINVALID_ARGUMENT) -{ - ON_CALL(service, GetValue(_, _, _)) - .WillByDefault(Return(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, ""))); - - string v; - uint32_t t; - EXPECT_THAT(store2->GetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, v, t), Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, GetsValueWithExpireTime) -{ - GetValueRequest req; - ON_CALL(service, GetValue(_, _, _)) - .WillByDefault(Invoke( - [&](::grpc::ServerContext*, const GetValueRequest* request, GetValueResponse* response) { - req = (*request); - auto v = new Value(); - v->set_value(kValue); - auto t = new google::protobuf::Timestamp(); - t->set_seconds(kTtl + (Time::Now().Ticks() / Time::TicksPerMillisecond / 1000)); - v->set_allocated_expire_time(t); - auto k = new Key(); - k->set_key(request->key().key()); - k->set_app_id(request->key().app_id()); - k->set_scope(request->key().scope()); - v->set_allocated_key(k); - response->set_allocated_value(v); - return grpc::Status::OK; - })); - - string v; - uint32_t t; - ASSERT_THAT(store2->GetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, v, t), Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(req.has_key(), IsTrue()); - EXPECT_THAT(req.key().key(), Eq(kKey)); - EXPECT_THAT(req.key().app_id(), Eq(kAppId)); - EXPECT_THAT(req.key().scope(), Eq(kScope)); - EXPECT_THAT(v, Eq(kValue)); - EXPECT_THAT(t, Le(kTtl)); - EXPECT_THAT(t, Gt(0)); -} - -TEST_F(AStore2, SetsValueWithTtl) -{ - UpdateValueRequest req; - ON_CALL(service, UpdateValue(_, _, _)) - .WillByDefault(Invoke( - [&](::grpc::ServerContext*, const UpdateValueRequest* request, UpdateValueResponse*) { - req = (*request); - return grpc::Status::OK; - })); - - ASSERT_THAT(store2->SetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, kValue, kTtl), Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(req.has_value(), IsTrue()); - EXPECT_THAT(req.value().value(), Eq(kValue)); - ASSERT_THAT(req.value().has_key(), IsTrue()); - EXPECT_THAT(req.value().key().key(), Eq(kKey)); - EXPECT_THAT(req.value().key().app_id(), Eq(kAppId)); - EXPECT_THAT(req.value().key().scope(), Eq(kScope)); - ASSERT_THAT(req.value().has_ttl(), IsTrue()); - EXPECT_THAT(req.value().ttl().seconds(), Eq(kTtl)); -} - -TEST_F(AStore2, DoesNotSetValueWhenINVALID_ARGUMENT) -{ - ON_CALL(service, UpdateValue(_, _, _)) - .WillByDefault(Return(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, ""))); - - EXPECT_THAT(store2->SetValue(IStore2::ScopeType::ACCOUNT, kAppId, kKey, kValue, kTtl), Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DeletesKey) -{ - DeleteValueRequest req; - ON_CALL(service, DeleteValue(_, _, _)) - .WillByDefault(Invoke( - [&](::grpc::ServerContext*, const DeleteValueRequest* request, DeleteValueResponse*) { - req = (*request); - return grpc::Status::OK; - })); - - ASSERT_THAT(store2->DeleteKey(IStore2::ScopeType::ACCOUNT, kAppId, kKey), Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(req.has_key(), IsTrue()); - EXPECT_THAT(req.key().key(), Eq(kKey)); - EXPECT_THAT(req.key().app_id(), Eq(kAppId)); - EXPECT_THAT(req.key().scope(), Eq(kScope)); -} - -TEST_F(AStore2, DoesNotDeleteKeyWhenINVALID_ARGUMENT) -{ - ON_CALL(service, DeleteValue(_, _, _)) - .WillByDefault(Return(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, ""))); - - EXPECT_THAT(store2->DeleteKey(IStore2::ScopeType::ACCOUNT, kAppId, kKey), Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DeletesNamespace) -{ - DeleteAllValuesRequest req; - ON_CALL(service, DeleteAllValues(_, _, _)) - .WillByDefault(Invoke( - [&](::grpc::ServerContext*, const DeleteAllValuesRequest* request, DeleteAllValuesResponse*) { - req = (*request); - return grpc::Status::OK; - })); - - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::ACCOUNT, kAppId), Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(req.app_id(), Eq(kAppId)); - EXPECT_THAT(req.scope(), Eq(kScope)); -} diff --git a/CloudStore/grpc/l0test/WorkerPoolImplementation.h b/CloudStore/grpc/l0test/WorkerPoolImplementation.h deleted file mode 100644 index fd57763..0000000 --- a/CloudStore/grpc/l0test/WorkerPoolImplementation.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../../Module.h" - -class WorkerPoolImplementation - : public WPEFramework::Core::WorkerPool, - public WPEFramework::Core::ThreadPool::ICallback { -private: - class Dispatcher : public WPEFramework::Core::ThreadPool::IDispatcher { - public: - Dispatcher(const Dispatcher&) = delete; - Dispatcher& operator=(const Dispatcher&) = delete; - Dispatcher() = default; - ~Dispatcher() override = default; - - private: - void Initialize() override - { - } - void Deinitialize() override - { - } - void Dispatch(WPEFramework::Core::IDispatch* job) override - { - job->Dispatch(); - } - }; - -public: - WorkerPoolImplementation() = delete; - WorkerPoolImplementation(const WorkerPoolImplementation&) = delete; - WorkerPoolImplementation& operator=(const WorkerPoolImplementation&) = delete; - WorkerPoolImplementation(const uint32_t stackSize) - : WPEFramework::Core::WorkerPool(4 /*threadCount*/, stackSize, 32 /*queueSize*/, &_dispatch, this) - , _dispatch() - { - Run(); - } - ~WorkerPoolImplementation() override - { - Stop(); - } - void Idle() override - { - } - -private: - Dispatcher _dispatch; -}; diff --git a/CloudStore/grpc/l2test/CMakeLists.txt b/CloudStore/grpc/l2test/CMakeLists.txt deleted file mode 100644 index e4a1d39..0000000 --- a/CloudStore/grpc/l2test/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -project(grpcl2test) - -set(CMAKE_CXX_STANDARD 11) - -add_executable(${PROJECT_NAME} - StubTest.cpp -) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) -FetchContent_MakeAvailable(googletest) -target_link_libraries(${PROJECT_NAME} PRIVATE gmock_main) - -find_package(Protobuf REQUIRED) -target_link_libraries(${PROJECT_NAME} PRIVATE ${Protobuf_LIBRARIES}) - -add_custom_target(protoc - ${Protobuf_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto -) -add_dependencies(${PROJECT_NAME} protoc) - -target_link_libraries(${PROJECT_NAME} PRIVATE grpc++) -find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) - -add_custom_target(protoc-gen-grpc - ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto -) -add_dependencies(${PROJECT_NAME} protoc-gen-grpc) - -set(PROTO_SRCS secure_storage.pb.cc secure_storage.grpc.pb.cc) -target_sources(${PROJECT_NAME} PRIVATE ${PROTO_SRCS}) -set_property(SOURCE ${PROTO_SRCS} PROPERTY GENERATED 1) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/CloudStore/grpc/l2test/StubTest.cpp b/CloudStore/grpc/l2test/StubTest.cpp deleted file mode 100644 index 9d48d4f..0000000 --- a/CloudStore/grpc/l2test/StubTest.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include - -#include "secure_storage.grpc.pb.h" -#include - -using ::distp::gateway::secure_storage::v1::DeleteAllValuesRequest; -using ::distp::gateway::secure_storage::v1::DeleteAllValuesResponse; -using ::distp::gateway::secure_storage::v1::DeleteValueRequest; -using ::distp::gateway::secure_storage::v1::DeleteValueResponse; -using ::distp::gateway::secure_storage::v1::GetValueRequest; -using ::distp::gateway::secure_storage::v1::GetValueResponse; -using ::distp::gateway::secure_storage::v1::Key; -using ::distp::gateway::secure_storage::v1::Scope; -using ::distp::gateway::secure_storage::v1::SecureStorageService; -using ::distp::gateway::secure_storage::v1::UpdateValueRequest; -using ::distp::gateway::secure_storage::v1::UpdateValueResponse; -using ::distp::gateway::secure_storage::v1::Value; -using ::testing::Eq; -using ::testing::Gt; -using ::testing::IsFalse; -using ::testing::IsTrue; -using ::testing::Le; -using ::testing::Test; - -const auto kUri = ""; -const auto kDevUri = ""; -const auto kValue = "value_1"; -const auto kKey = "key_1"; -const auto kAppId = "app_id_1"; -const auto kTtl = 2; -const auto kTtlFault = 1; -const auto kScope = Scope::SCOPE_ACCOUNT; -const auto kEmpty = ""; -const auto kUnknown = "unknown"; -const auto kToken = "Bearer TOKEN"; - -class AStub : public Test { -protected: - std::unique_ptr stub; - AStub() - : stub(SecureStorageService::NewStub(grpc::CreateChannel( - kUri, - grpc::SslCredentials(grpc::SslCredentialsOptions())))) - { - } -}; - -class ADevStub : public Test { -protected: - std::unique_ptr stub; - ADevStub() - : stub(SecureStorageService::NewStub(grpc::CreateChannel( - kDevUri, - grpc::SslCredentials(grpc::SslCredentialsOptions())))) - { - } -}; - -TEST_F(AStub, DoesNotUpdateValueWhenAppIdEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto k = new Key(); - k->set_app_id(kEmpty); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("key's key and app_id fields are required")); -} - -TEST_F(AStub, DoesNotUpdateValueWhenKeyEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kEmpty); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("invalid UpdateValueRequest.Value: embedded message failed validation | caused by: invalid Value.Key: embedded message failed validation | caused by: invalid Key.Key: value length must be at least 1 runes")); -} - -TEST_F(AStub, DoesNotGetValueWhenAppIdEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kEmpty); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("key's key and app_id fields are required")); -} - -TEST_F(AStub, DoesNotGetValueWhenKeyEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kEmpty); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("invalid GetValueRequest.Key: embedded message failed validation | caused by: invalid Key.Key: value length must be at least 1 runes")); -} - -TEST_F(AStub, DoesNotDeleteValueWhenAppIdEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteValueRequest request; - auto k = new Key(); - k->set_app_id(kEmpty); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - DeleteValueResponse response; - auto status = stub->DeleteValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("key's key and app_id fields are required")); -} - -TEST_F(AStub, DoesNotDeleteValueWhenKeyEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kEmpty); - k->set_scope(kScope); - request.set_allocated_key(k); - DeleteValueResponse response; - auto status = stub->DeleteValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(3)); - EXPECT_THAT(status.error_message(), Eq("invalid DeleteValueRequest.Key: embedded message failed validation | caused by: invalid Key.Key: value length must be at least 1 runes")); -} - -TEST_F(AStub, DeletesAllValuesWhenAppIdEmpty) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteAllValuesRequest request; - request.set_app_id(kEmpty); - request.set_scope(kScope); - DeleteAllValuesResponse response; - auto status = stub->DeleteAllValues(&context, request, &response); - EXPECT_THAT(status.ok(), IsTrue()); -} - -TEST_F(AStub, GetsValueWhenValueEmpty) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kEmpty); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - ASSERT_THAT(response.has_value(), IsTrue()); - EXPECT_THAT(response.value().value(), Eq(kEmpty)); - EXPECT_THAT(response.value().has_ttl(), IsFalse()); - EXPECT_THAT(response.value().has_expire_time(), IsFalse()); - } -} - -TEST_F(AStub, DoesNotGetValueWhenAppIdUnknown) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kUnknown); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - EXPECT_THAT(response.has_value(), IsFalse()); -} - -TEST_F(ADevStub, DoesNotGetValueWhenAppIdUnknown) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kUnknown); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(5)); - EXPECT_THAT(status.error_message(), Eq("requested key scope does not exist")); -} - -TEST_F(AStub, DoesNotGetValueWhenKeyUnknown) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kUnknown); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - EXPECT_THAT(response.has_value(), IsFalse()); - } -} - -TEST_F(ADevStub, DoesNotGetValueWhenKeyUnknown) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kUnknown); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(5)); - EXPECT_THAT(status.error_message(), Eq("requested key scope does not exist")); - } -} - -TEST_F(AStub, DeletesValueWhenAppIdUnknown) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteValueRequest request; - auto k = new Key(); - k->set_app_id(kUnknown); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - DeleteValueResponse response; - auto status = stub->DeleteValue(&context, request, &response); - EXPECT_THAT(status.ok(), IsTrue()); -} - -TEST_F(AStub, DeletesValueWhenKeyUnknown) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kUnknown); - k->set_scope(kScope); - request.set_allocated_key(k); - DeleteValueResponse response; - auto status = stub->DeleteValue(&context, request, &response); - EXPECT_THAT(status.ok(), IsTrue()); - } -} - -TEST_F(AStub, DeletesAllValuesWhenAppIdUnknown) -{ - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - DeleteAllValuesRequest request; - request.set_app_id(kUnknown); - request.set_scope(kScope); - DeleteAllValuesResponse response; - auto status = stub->DeleteAllValues(&context, request, &response); - EXPECT_THAT(status.ok(), IsTrue()); -} - -TEST_F(AStub, GetsValueWhenTtlDidNotExpire) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto t = new ::google::protobuf::Duration(); - t->set_seconds(kTtl); - v->set_allocated_ttl(t); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - ASSERT_THAT(response.has_value(), IsTrue()); - EXPECT_THAT(response.value().value(), Eq(kValue)); - EXPECT_THAT(response.value().has_ttl(), IsFalse()); - ASSERT_THAT(response.value().has_expire_time(), IsTrue()); - ::google::protobuf::Timestamp now; - now.set_seconds(time(nullptr)); - now.set_nanos(0); - EXPECT_THAT(response.value().expire_time().seconds(), Gt(now.seconds())); - EXPECT_THAT(response.value().expire_time().seconds(), Le(now.seconds() + kTtl + kTtlFault)); - } -} - -TEST_F(AStub, DoesNotGetValueWhenTtlExpired) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto t = new ::google::protobuf::Duration(); - t->set_seconds(kTtl); - v->set_allocated_ttl(t); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - sleep(kTtl + kTtlFault); - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - EXPECT_THAT(response.has_value(), IsFalse()); - } -} - -TEST_F(ADevStub, DoesNotGetValueWhenTtlExpired) -{ - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - UpdateValueRequest request; - auto v = new Value(); - v->set_value(kValue); - auto t = new ::google::protobuf::Duration(); - t->set_seconds(kTtl); - v->set_allocated_ttl(t); - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - v->set_allocated_key(k); - request.set_allocated_value(v); - UpdateValueResponse response; - auto status = stub->UpdateValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsTrue()); - } - sleep(kTtl + kTtlFault); - { - grpc::ClientContext context; - context.AddMetadata("authorization", std::string(kToken)); - GetValueRequest request; - auto k = new Key(); - k->set_app_id(kAppId); - k->set_key(kKey); - k->set_scope(kScope); - request.set_allocated_key(k); - GetValueResponse response; - auto status = stub->GetValue(&context, request, &response); - ASSERT_THAT(status.ok(), IsFalse()); - EXPECT_THAT(status.error_code(), Eq(5)); - EXPECT_THAT(status.error_message(), Eq("requested key scope does not exist")); - } -} diff --git a/CloudStore/grpc/secure_storage/secure_storage.proto b/CloudStore/grpc/secure_storage/secure_storage.proto deleted file mode 100644 index a724f03..0000000 --- a/CloudStore/grpc/secure_storage/secure_storage.proto +++ /dev/null @@ -1,209 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto3"; - -package distp.gateway.secure_storage.v1; - -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; - -// SecureStorageService handles the storage and deletion of data (represented -// as string values) from applications given a particular key and scope. -service SecureStorageService { - // GetValue retrieves the value string stored in SecureStorage based on the - // scope and key provided for the current application. - rpc GetValue(GetValueRequest) returns (GetValueResponse); - - // UpdateValue stores the string value provided in SecureStorage against the - // scope and key provided for the current application. - rpc UpdateValue(UpdateValueRequest) returns (UpdateValueResponse); - - // DeleteValue removes the string value stored in SecureStorage, if present, - // defined by the scope and key provided for the current application/device. - rpc DeleteValue(DeleteValueRequest) returns (DeleteValueResponse); - - // DeleteAllValues removes all values stored against the provided application - // for the given account. This includes all key/value pairs stored against - // the device scope for other devices within the account. Please note that - // this method does not take a key as input. Also, DeleteAllValues is a - // separate method given that access to delete all values may be controlled - // by explicit capabilities. - rpc DeleteAllValues(DeleteAllValuesRequest) returns (DeleteAllValuesResponse); - - // SeedValue stores the string value provided in SecureStorage against the - // scope and key provided for the current application. This is a management - // API so the stored value will not cause the distributor's storage limits to - // be exceeded. - rpc SeedValue(SeedValueRequest) returns (SeedValueResponse); -} - -// Key is a group of fields that contribute to building the composite key that -// will be used to store the data in SecureStorage. -message Key { - // key of the key,value pair to be retrieved from SecureStorage. - string key = 1; - - // Scope describes the extent of the key,value pair. Scope is determined by - // the distributor. - Scope scope = 2; - - // app_id is the unique identifier of an app or family of apps. - string app_id = 3; -} - -// Value contains the value of the requested data as well as some other -// relevant fields like scope and expiry useful for the client. -message Value { - // key of the key,value pair that was retrieved from SecureStorage. - Key key = 1; - - // value is the value associated with the key,value pair retrieved from - // SecureStorage. - string value = 2; - - // expiration returns the expire time of the retrieved value. Conforms to - // AIP-214. - oneof expiration { - // Timestamp in UTC of when this resource is considered expired. This is - // *always* provided on output, regardless of what was sent on input. - google.protobuf.Timestamp expire_time = 3; - - // Input only. The TTL for this resource. - google.protobuf.Duration ttl = 4; - } -} - -// GetValueRequest is the request to retrieve the SecureStorage data. -message GetValueRequest { - // XBO ID for the partner making the request - string partner_id = 3; - - // XBO ID for the account making the request - string account_id = 4; - - // XBO ID for the device making the request - string device_id = 2; - - // key is the group of fields that contribute to building the composite key - // that will be used to store the data in SecureStorage. - Key key = 1; -} - -// GetValueResponse is the response containing the value of the requested key -// within the specified scope. -message GetValueResponse { - // value contains the data associated with the key,value pair that was stored - // in SecureStorage. - Value value = 1; -} - -// UpdateValueRequest is the request to store data in SecureStorage. -message UpdateValueRequest { - // XBO ID for the partner making the request - string partner_id = 3; - - // XBO ID for the account making the request - string account_id = 4; - - // XBO ID for the device making the request - string device_id = 2; - - // The key-value pair that will be upserted into the secure storage database. - Value value = 1; -} - -// UpdateValueResponse is the response from the GetValue method. -message UpdateValueResponse {} - -// DeleteValueRequest is the request to remove a stored value given the key and -// scope. -message DeleteValueRequest { - // XBO ID for the partner making the request - string partner_id = 3; - - // XBO ID for the account making the request - string account_id = 4; - - // XBO ID for the device making the request - string device_id = 2; - - // Key is the group of fields that contribute to building the composite key - // that will be used to store the data in SecureStorage. - Key key = 1; -} - -// DeleteValueResponse is the response from the DeleteValue method. -message DeleteValueResponse {} - -// DeleteAllValuesRequest is the request to delete all of the keys associated -// with an app under the given account. -message DeleteAllValuesRequest { - // XBO ID for the partner making the request - string partner_id = 3; - - // XBO ID for the account making the request - string account_id = 4; - - // XBO ID for the device making the request - string device_id = 5; - - // app_id is the unique identifier of an app or family of apps. - string app_id = 1; - - // Scope describes the extent of the key,value pair. Scope is determined by - // the distributor. - Scope scope = 2; -} - -// DeleteAllValuesResponse is the response from the DeleteAllValues method. -message DeleteAllValuesResponse {} - -// SeedValueRequest is the request to store data in SecureStorage. Stored data -// will not cause the distributor's storage limits to be exceeded. -message SeedValueRequest { - // ID of the partner this change applies to. This field is optional IFF - // exactly one partner is provided in the request SAT. - string partner_id = 4; - - // XBO ID for the account making the request - string account_id = 2; - - // XBO ID for the device making the request - string device_id = 3; - - // value contains the data associated with the key,value pair that will be - // stored in SecureStorage. - Value value = 1; -} - -// SeedValueResponse is the response from the SeedValue method. -message SeedValueResponse {} - -// Enumerated values for scope. -enum Scope { - // Represents an unset or invalid scope. - SCOPE_UNSPECIFIED = 0; - - // Account scope. - SCOPE_ACCOUNT = 1; - - // Device scope. - SCOPE_DEVICE = 2; -} diff --git a/CloudStore/l0test/CMakeLists.txt b/CloudStore/l0test/CMakeLists.txt deleted file mode 100644 index d5b0319..0000000 --- a/CloudStore/l0test/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -project(cloudstorel0test) - -set(CMAKE_CXX_STANDARD 11) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) -FetchContent_MakeAvailable(googletest) - -find_package(WPEFramework NAMES WPEFramework Thunder) -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) - -add_executable(${PROJECT_NAME} - ../Module.cpp - ../CloudStore.cpp - CloudStoreTest.cpp -) - -target_link_libraries(${PROJECT_NAME} PRIVATE - gmock_main - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/CloudStore/l0test/CloudStoreImplementationMock.h b/CloudStore/l0test/CloudStoreImplementationMock.h deleted file mode 100644 index a36d8e5..0000000 --- a/CloudStore/l0test/CloudStoreImplementationMock.h +++ /dev/null @@ -1,60 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include - -class CloudStoreImplementationMock - : public WPEFramework::Exchange::IStore, - public WPEFramework::Exchange::IStore2, - public WPEFramework::Exchange::IStoreCache, - public WPEFramework::Exchange::IStoreInspector, - public WPEFramework::Exchange::IStoreLimit { -public: - ~CloudStoreImplementationMock() override = default; - MOCK_METHOD(uint32_t, Register, (IStore::INotification * notification), (override)); - MOCK_METHOD(uint32_t, Unregister, (IStore::INotification * notification), (override)); - MOCK_METHOD(uint32_t, SetValue, (const string& ns, const string& key, const string& value), (override)); - MOCK_METHOD(uint32_t, GetValue, (const string& ns, const string& key, string& value), (override)); - MOCK_METHOD(uint32_t, DeleteKey, (const string& ns, const string& key), (override)); - MOCK_METHOD(uint32_t, DeleteNamespace, (const string& ns), (override)); - MOCK_METHOD(uint32_t, Register, (IStore2::INotification*), (override)); - MOCK_METHOD(uint32_t, Unregister, (IStore2::INotification*), (override)); - MOCK_METHOD(uint32_t, SetValue, (const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl), (override)); - MOCK_METHOD(uint32_t, GetValue, (const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl), (override)); - MOCK_METHOD(uint32_t, DeleteKey, (const IStore2::ScopeType scope, const string& ns, const string& key), (override)); - MOCK_METHOD(uint32_t, DeleteNamespace, (const IStore2::ScopeType scope, const string& ns), (override)); - MOCK_METHOD(uint32_t, FlushCache, (), (override)); - MOCK_METHOD(uint32_t, GetKeys, (const IStoreInspector::ScopeType scope, const string& ns, IStringIterator*& keys), (override)); - MOCK_METHOD(uint32_t, GetNamespaces, (const IStoreInspector::ScopeType scope, IStringIterator*& namespaces), (override)); - MOCK_METHOD(uint32_t, GetStorageSizes, (const IStoreInspector::ScopeType scope, INamespaceSizeIterator*& storageList), (override)); - MOCK_METHOD(uint32_t, GetNamespaceStorageLimit, (const IStoreLimit::ScopeType scope, const string& ns, uint32_t& size), (override)); - MOCK_METHOD(uint32_t, SetNamespaceStorageLimit, (const IStoreLimit::ScopeType scope, const string& ns, const uint32_t size), (override)); - BEGIN_INTERFACE_MAP(CloudStoreImplementationMock) - INTERFACE_ENTRY(IStore) - INTERFACE_ENTRY(IStore2) - INTERFACE_ENTRY(IStoreCache) - INTERFACE_ENTRY(IStoreInspector) - INTERFACE_ENTRY(IStoreLimit) - END_INTERFACE_MAP -}; diff --git a/CloudStore/l0test/CloudStoreTest.cpp b/CloudStore/l0test/CloudStoreTest.cpp deleted file mode 100644 index e09c888..0000000 --- a/CloudStore/l0test/CloudStoreTest.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "../CloudStore.h" -#include "CloudStoreImplementationMock.h" -#include "ServiceMock.h" -#include - -using ::testing::_; -using ::testing::Eq; -using ::testing::Invoke; -using ::testing::NiceMock; -using ::testing::NotNull; -using ::testing::Return; -using ::testing::Test; -using ::WPEFramework::Core::PublishedServiceType; -using ::WPEFramework::Exchange::IStore2; -using ::WPEFramework::JsonData::Store2::DeleteNamespaceParamsData; -using ::WPEFramework::JsonData::Store2::GetValueParamsInfo; -using ::WPEFramework::JsonData::Store2::GetValueResultData; -using ::WPEFramework::JsonData::Store2::SetValueParamsData; -using ::WPEFramework::Plugin::CloudStore; -using ::WPEFramework::PluginHost::IDispatcher; -using ::WPEFramework::PluginHost::IPlugin; - -const auto kValue = "value_1"; -const auto kKey = "key_1"; -const auto kAppId = "app_id_1"; -const auto kTtl = 100; - -class ACloudStore : public Test { -protected: - NiceMock* service; - IPlugin* plugin; - ACloudStore() - : service(WPEFramework::Core::Service>::Create>()) - , plugin(WPEFramework::Core::Service::Create()) - { - } - ~ACloudStore() override - { - plugin->Release(); - service->Release(); - } -}; - -TEST_F(ACloudStore, GetsValueInAccountScopeViaJsonRpc) -{ - class CloudStoreImplementation : public NiceMock { - public: - CloudStoreImplementation() - { - EXPECT_CALL(*this, GetValue(_, _, _, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - value = kValue; - ttl = kTtl; - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - GetValueParamsInfo params; - params.Scope = IStore2::ScopeType::ACCOUNT; - params.Ns = kAppId; - params.Key = kKey; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - ASSERT_THAT(jsonRpc->Invoke(0, 0, "", "getValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - GetValueResultData result; - result.FromString(resultJsonStr); - EXPECT_THAT(result.Value.Value(), Eq(kValue)); - EXPECT_THAT(result.Ttl.Value(), Eq(kTtl)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - -TEST_F(ACloudStore, SetsValueInAccountScopeViaJsonRpc) -{ - class CloudStoreImplementation : public NiceMock { - public: - CloudStoreImplementation() - { - EXPECT_CALL(*this, SetValue(_, _, _, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - EXPECT_THAT(value, Eq(kValue)); - EXPECT_THAT(ttl, Eq(kTtl)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - SetValueParamsData params; - params.Scope = IStore2::ScopeType::ACCOUNT; - params.Ns = kAppId; - params.Key = kKey; - params.Value = kValue; - params.Ttl = kTtl; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "setValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - -TEST_F(ACloudStore, DeletesKeyInAccountScopeViaJsonRpc) -{ - class CloudStoreImplementation : public NiceMock { - public: - CloudStoreImplementation() - { - EXPECT_CALL(*this, DeleteKey(_, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - GetValueParamsInfo params; - params.Scope = IStore2::ScopeType::ACCOUNT; - params.Ns = kAppId; - params.Key = kKey; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteKey", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - -TEST_F(ACloudStore, DeletesNamespaceInAccountScopeViaJsonRpc) -{ - class CloudStoreImplementation : public NiceMock { - public: - CloudStoreImplementation() - { - EXPECT_CALL(*this, DeleteNamespace(_, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - DeleteNamespaceParamsData params; - params.Scope = IStore2::ScopeType::ACCOUNT; - params.Ns = kAppId; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteNamespace", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} diff --git a/CloudStore/l0test/ServiceMock.h b/CloudStore/l0test/ServiceMock.h deleted file mode 100644 index df4e06f..0000000 --- a/CloudStore/l0test/ServiceMock.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../Module.h" -#include - -class ServiceMock : public WPEFramework::PluginHost::IShell, - public WPEFramework::PluginHost::IShell::ICOMLink { -public: - ~ServiceMock() override = default; - MOCK_METHOD(string, Versions, (), (const, override)); - MOCK_METHOD(string, Locator, (), (const, override)); - MOCK_METHOD(string, ClassName, (), (const, override)); - MOCK_METHOD(string, Callsign, (), (const, override)); - MOCK_METHOD(string, WebPrefix, (), (const, override)); - MOCK_METHOD(string, ConfigLine, (), (const, override)); - MOCK_METHOD(string, PersistentPath, (), (const, override)); - MOCK_METHOD(string, VolatilePath, (), (const, override)); - MOCK_METHOD(string, DataPath, (), (const, override)); - MOCK_METHOD(state, State, (), (const, override)); - MOCK_METHOD(bool, Resumed, (), (const, override)); - MOCK_METHOD(bool, IsSupported, (const uint8_t), (const, override)); - MOCK_METHOD(void, EnableWebServer, (const string&, const string&), (override)); - MOCK_METHOD(void, DisableWebServer, (), (override)); - MOCK_METHOD(WPEFramework::PluginHost::ISubSystem*, SubSystems, (), (override)); - MOCK_METHOD(uint32_t, Submit, (const uint32_t, const WPEFramework::Core::ProxyType&), (override)); - MOCK_METHOD(void, Notify, (const string&, const string&), (override)); - MOCK_METHOD(void*, QueryInterfaceByCallsign, (const uint32_t, const string&), (override)); - MOCK_METHOD(void, Register, (WPEFramework::PluginHost::IPlugin::INotification*), (override)); - MOCK_METHOD(void, Unregister, (WPEFramework::PluginHost::IPlugin::INotification*), (override)); - MOCK_METHOD(string, Model, (), (const, override)); - MOCK_METHOD(bool, Background, (), (const, override)); - MOCK_METHOD(string, Accessor, (), (const, override)); - MOCK_METHOD(string, ProxyStubPath, (), (const, override)); - MOCK_METHOD(string, HashKey, (), (const, override)); - MOCK_METHOD(string, Substitute, (const string&), (const, override)); - MOCK_METHOD(uint32_t, Activate, (const reason), (override)); - MOCK_METHOD(uint32_t, Deactivate, (const reason), (override)); - MOCK_METHOD(uint32_t, Unavailable, (const reason), (override)); - MOCK_METHOD(reason, Reason, (), (const, override)); - MOCK_METHOD(uint32_t, ConfigLine, (const string&), (override)); - MOCK_METHOD(string, SystemRootPath, (), (const, override)); - MOCK_METHOD(uint32_t, SystemRootPath, (const string&), (override)); - MOCK_METHOD(string, SystemPath, (), (const, override)); - MOCK_METHOD(string, PluginPath, (), (const, override)); - MOCK_METHOD(WPEFramework::PluginHost::IShell::startmode, StartMode, (), (const, override)); - MOCK_METHOD(WPEFramework::Core::hresult, StartMode, (const startmode), (override)); - MOCK_METHOD(WPEFramework::Core::hresult, Resumed, (const bool), (override)); - MOCK_METHOD(WPEFramework::Core::hresult, Metadata, (string&), (const, override)); - MOCK_METHOD(WPEFramework::Core::hresult, Hibernate, (const uint32_t), (override)); - MOCK_METHOD(void, Register, (WPEFramework::RPC::IRemoteConnection::INotification*), (override)); - MOCK_METHOD(void, Unregister, (const WPEFramework::RPC::IRemoteConnection::INotification*), (override)); - MOCK_METHOD(void, Register, (IShell::ICOMLink::INotification*), (override)); - MOCK_METHOD(void, Unregister, (const IShell::ICOMLink::INotification*), (override)); - MOCK_METHOD(WPEFramework::RPC::IRemoteConnection*, RemoteConnection, (const uint32_t), (override)); - MOCK_METHOD(void*, Instantiate, (WPEFramework::RPC::Object&, const uint32_t, uint32_t&), (override)); - MOCK_METHOD(WPEFramework::RPC::IStringIterator*, GetLibrarySearchPaths, (const string&), (const, override)); - BEGIN_INTERFACE_MAP(ServiceMock) - INTERFACE_ENTRY(IShell) - INTERFACE_ENTRY(IShell::ICOMLink) - END_INTERFACE_MAP -}; diff --git a/DownloadManager/CMakeLists.txt b/DownloadManager/CMakeLists.txt deleted file mode 100755 index fe5bf52..0000000 --- a/DownloadManager/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2025 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME DownloadManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_DOWNLOADMANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_DOWNLOADMANAGER_AUTOSTART "false" CACHE STRING "Automatically start Download Manager plugin") -set(PLUGIN_DOWNLOADMANAGER_STARTUPORDER "" CACHE STRING "Automatically start Download Manager plugin") -set(PLUGIN_DOWNLOADMANAGER_DOWNLOAD_DIR "/opt/CDL/" CACHE STRING "Setting Default Download directory path") -set(PLUGIN_DOWNLOADMANAGER_DOWNLOAD_ID "2000" CACHE STRING "Setting Default Download id") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - DownloadManager.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - DownloadManagerImplementation.cpp - Module.cpp - DownloadManagerHttpClient.cpp) - -include_directories( - ../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -if(RDK_SERVICES_L1_TEST) - find_path(JSONCPP_INCLUDE_DIR json/json.h PATHS /usr/include/jsoncpp) - include_directories(${JSONCPP_INCLUDE_DIR}) - target_include_directories(${MODULE_NAME} PUBLIC ${JSONCPP_INCLUDE_DIR}) -endif(RDK_SERVICES_L1_TEST) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) - - diff --git a/DownloadManager/DownloadManager.conf.in b/DownloadManager/DownloadManager.conf.in deleted file mode 100755 index 42178a2..0000000 --- a/DownloadManager/DownloadManager.conf.in +++ /dev/null @@ -1,13 +0,0 @@ -autostart = "@PLUGIN_DOWNLOADMANAGER_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.@PLUGIN_NAME@" -startuporder = "@PLUGIN_DOWNLOADMANAGER_STARTUPORDER@" - -configuration = JSON() - -root = JSON() -root.add("mode", "@PLUGIN_DOWNLOADMANAGER_MODE@") -root.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", root) -configuration.add("downloadDir", "@PLUGIN_DOWNLOADMANAGER_DOWNLOAD_DIR@") -configuration.add("downloadId", "@PLUGIN_DOWNLOADMANAGER_DOWNLOAD_ID@") \ No newline at end of file diff --git a/DownloadManager/DownloadManager.config b/DownloadManager/DownloadManager.config deleted file mode 100755 index f6a86d0..0000000 --- a/DownloadManager/DownloadManager.config +++ /dev/null @@ -1,17 +0,0 @@ -set (autostart false) -set (preconditions Platform) -set (callsign "org.rdk.DownloadManager") - -if(PLUGIN_DOWNLOADMANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_DOWNLOADMANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_DOWNLOADMANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) - diff --git a/DownloadManager/DownloadManager.cpp b/DownloadManager/DownloadManager.cpp deleted file mode 100755 index 1edace0..0000000 --- a/DownloadManager/DownloadManager.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "DownloadManager.h" - -namespace WPEFramework { - -namespace Plugin -{ - - namespace { - static Metadata metadata( - // Version - 1, 0, 0, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - DownloadManager::DownloadManager() - : mConnectionId(0) - , mService(nullptr) - , mDownloadManagerImpl(nullptr) - , mNotificationSink(*this) - { - } - - const string DownloadManager::Initialize(PluginHost::IShell * service) - { - string message; - - ASSERT(service != nullptr); - ASSERT(mService == nullptr); - ASSERT(mConnectionId == 0); - ASSERT(mDownloadManagerImpl == nullptr); - mService = service; - mService->AddRef(); - - LOGINFO(); - // Register the Process::Notification stuff. The Remote process might die before we get a - // change to "register" the sink for these events !!! So do it ahead of instantiation. - mService->Register(&mNotificationSink); - - mDownloadManagerImpl = service->Root(mConnectionId, RPC::CommunicationTimeOut, _T("DownloadManagerImplementation")); - if (mDownloadManagerImpl != nullptr) - { - mDownloadManagerImpl->Initialize(service); - - mDownloadManagerImpl->Register(&mNotificationSink); - Exchange::JDownloadManager::Register(*this, mDownloadManagerImpl); - } - else - { - message = _T("DownloadManager could not be instantiated."); - } - - // On success return empty, to indicate there is no error text. - return (message); - } - - void DownloadManager::Deinitialize(PluginHost::IShell* service) - { - LOGINFO(); - if (mService != nullptr) - { - ASSERT(mService == service); - mService->Unregister(&mNotificationSink); - if (mDownloadManagerImpl != nullptr) - { - mDownloadManagerImpl->Unregister(&mNotificationSink); - Exchange::JDownloadManager::Unregister(*this); - - if (nullptr != mService) - { - mDownloadManagerImpl->Deinitialize(mService); - } - - RPC::IRemoteConnection* connection(mService->RemoteConnection(mConnectionId)); - if (mDownloadManagerImpl->Release() != Core::ERROR_DESTRUCTION_SUCCEEDED) - { - LOGERR("DownloadManager Plugin is not properly destructed. %d", mConnectionId); - } - mDownloadManagerImpl = nullptr; - - // The connection can disappear in the meantime... - if (connection != nullptr) - { - // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill :-) - connection->Terminate(); - connection->Release(); - } - } - - mService->Release(); - mService = nullptr; - mConnectionId = 0; - SYSLOG(Logging::Shutdown, (string(_T("DownloadManager de-initialised")))); - } - } - - string DownloadManager::Information() const - { - // No additional info to report. - return (string()); - } - - - void DownloadManager::Deactivated(RPC::IRemoteConnection* connection) - { - LOGINFO(); - // This can potentially be called on a socket thread, so the deactivation (wich in turn kills this object) must be done - // on a seperate thread. Also make sure this call-stack can be unwound before we are totally destructed. - if (mConnectionId == connection->Id()) - { - ASSERT(mService != nullptr); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - -} // namespace Plugin -} // namespace WPEFramework - diff --git a/DownloadManager/DownloadManager.h b/DownloadManager/DownloadManager.h deleted file mode 100755 index fb8bd72..0000000 --- a/DownloadManager/DownloadManager.h +++ /dev/null @@ -1,116 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" - -#include -#include - -#include "UtilsLogging.h" - -namespace WPEFramework { -namespace Plugin { - - class DownloadManager : public PluginHost::IPlugin, - public PluginHost::JSONRPC { - private: - class NotificationHandler - : public RPC::IRemoteConnection::INotification - , public Exchange::IDownloadManager::INotification - { - public: - NotificationHandler() = delete; - NotificationHandler(const NotificationHandler&) = delete; - NotificationHandler(NotificationHandler&&) = delete; - NotificationHandler& operator=(const NotificationHandler&) = delete; - NotificationHandler& operator=(NotificationHandler&&) = delete; - - NotificationHandler(DownloadManager& parent) - : mParent(parent) - { - } - ~NotificationHandler() override = default; - - public: - void Activated(RPC::IRemoteConnection* /* connection */) override - { - } - void Deactivated(RPC::IRemoteConnection* connection) override - { - mParent.Deactivated(connection); - } - void Terminated (RPC::IRemoteConnection* /* connection */) override - { - } - - void OnAppDownloadStatus(const string& jsonresponse) override - { - LOGTRACE(); - Exchange::JDownloadManager::Event::OnAppDownloadStatus(mParent, jsonresponse); - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - INTERFACE_ENTRY(Exchange::IDownloadManager::INotification) - END_INTERFACE_MAP - - private: - DownloadManager& mParent; - }; - public: - DownloadManager(const DownloadManager&) = delete; - DownloadManager(DownloadManager&&) = delete; - DownloadManager& operator=(const DownloadManager&) = delete; - DownloadManager& operator=(DownloadManager&) = delete; - - DownloadManager(); - ~DownloadManager() override = default; - - // Build QueryInterface implementation, specifying all possible interfaces to be returned. - BEGIN_INTERFACE_MAP(DownloadManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IDownloadManager, mDownloadManagerImpl) - END_INTERFACE_MAP - - public: - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - uint32_t mConnectionId; - PluginHost::IShell* mService; - Exchange::IDownloadManager* mDownloadManagerImpl; - - Core::Sink mNotificationSink; - - }; - -} // namespace Plugin -} // namespace WPEFramework - diff --git a/DownloadManager/DownloadManagerHttpClient.cpp b/DownloadManager/DownloadManagerHttpClient.cpp deleted file mode 100755 index 3cad23c..0000000 --- a/DownloadManager/DownloadManagerHttpClient.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include - -#include "Module.h" -#include "DownloadManagerHttpClient.h" - -DownloadManagerHttpClient::DownloadManagerHttpClient() - : curl(nullptr) - , httpCode(0) - , bCancel(false) - , progress(0) -{ - //curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - if (curl) - { - LOGDBG("curl initialized"); - } - else - { - LOGERR("curl initialize failed"); - } - } - -DownloadManagerHttpClient::~DownloadManagerHttpClient() -{ - std::lock_guard lock(mHttpClientMutex); - if (curl) - { - curl_easy_cleanup(curl); - } - //curl_global_cleanup(); -} - -DownloadManagerHttpClient::Status DownloadManagerHttpClient::downloadFile(const std::string & url, const std::string & fileName, uint32_t rateLimit) -{ - Status status = Status::Success; - CURLcode cc; - FILE *fp; - - std::unique_lock lock(mHttpClientMutex); - bCancel = false; - progress = 0; - httpCode = 0; - - if (curl) - { - (void) curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - LOGDBG("curl rateLimit set to %u", rateLimit); - curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)rateLimit); - - fp = fopen(fileName.c_str(), "wb"); - if (fp != NULL) - { - (void) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); - (void) curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - - (void) curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - (void) curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this); - (void) curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCb); - - /* Unlock before blocking call */ - lock.unlock(); - cc = curl_easy_perform(curl); - /* Re-lock mutex after curl call */ - lock.lock(); - curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &httpCode); - if (cc == CURLE_OK) - { - if (httpCode == 404) { - status = Status::HttpError; - LOGERR("Download %s Failed, code: %ld", fileName.c_str(), httpCode); - } else { - LOGDBG("Download %s Success", fileName.c_str()); - } - } - else - { - LOGERR("Download %s Failed error: %s code: %ld", fileName.c_str(), curl_easy_strerror(cc), httpCode); - if ( cc == CURLE_WRITE_ERROR ) { - status = Status::DiskError; - } else { - status = Status::HttpError; - } - } - fclose(fp); - } - else - { - LOGERR("Failed to open %s", fileName.c_str()); - status = Status::DiskError; - } - } - - return status; -} - -size_t DownloadManagerHttpClient::progressCb(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow) -{ - DownloadManagerHttpClient *pHttpClient = static_cast(ptr); - std::lock_guard lock(pHttpClient->mHttpClientMutex); - if (dltotal > 0.0) - { - uint8_t percent = static_cast((dlnow * 100) / dltotal); - pHttpClient->progress = percent; - //LOGDBG("%u%% completed dlnow=%f / dltotal=%f ulnow=%f / ultotal=%f", percent, dlnow, dltotal, ulnow, ultotal); - } - - /* If cancel requested, return non-zero to abort curl_easy_perform */ - return pHttpClient->bCancel ? 1 : 0; -} - -size_t DownloadManagerHttpClient::write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) { - // LOGTRACE("size=%ld nmemb=%ld", size, nmemb); - return fwrite(ptr, size, nmemb, stream); -} - diff --git a/DownloadManager/DownloadManagerHttpClient.h b/DownloadManager/DownloadManagerHttpClient.h deleted file mode 100755 index d938975..0000000 --- a/DownloadManager/DownloadManagerHttpClient.h +++ /dev/null @@ -1,83 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include - -#include "UtilsLogging.h" - -class DownloadManagerHttpClient { - public: - enum Status { - Success, - HttpError, - DiskError - }; - - DownloadManagerHttpClient(); - ~DownloadManagerHttpClient(); - - Status downloadFile(const std::string & url, const std::string & fileName, uint32_t rateLimit = 0); - - void pause() { - std::lock_guard lock(mHttpClientMutex); - curl_easy_pause(curl, CURLPAUSE_RECV | CURLPAUSE_SEND); - } - void resume() { - std::lock_guard lock(mHttpClientMutex); - curl_easy_pause(curl, CURLPAUSE_CONT); - } - void cancel() { - std::lock_guard lock(mHttpClientMutex); - bCancel = true; - } - void setRateLimit(uint32_t rateLimit) { - LOGDBG("curl rateLimit set to %u", rateLimit); - std::lock_guard lock(mHttpClientMutex); - (void) curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)rateLimit); - } - uint8_t getProgress() { - std::lock_guard lock(mHttpClientMutex); - return progress; - } - - // SSL - void setToken() {} - void setCert() {} - void setCertPath() {} - - long getStatusCode() { - std::lock_guard lock(mHttpClientMutex); - return httpCode; - } - - private: - static size_t progressCb(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow); - static size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream); - - private: - std::mutex mHttpClientMutex; - CURL *curl; - long httpCode = 0; - bool bCancel = false; - uint8_t progress = 0; -}; - diff --git a/DownloadManager/DownloadManagerImplementation.cpp b/DownloadManager/DownloadManagerImplementation.cpp deleted file mode 100755 index ba92df3..0000000 --- a/DownloadManager/DownloadManagerImplementation.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include - -#include "DownloadManagerImplementation.h" - -#define DOWNLOADER_DEFAULT_PATH_LOCATION "/opt/CDL/" -#define DOWNLOADER_DOWNLOAD_ID_START (2000) - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(DownloadManagerImplementation, 1, 0); - - DownloadManagerImplementation::DownloadManagerImplementation() - : mDownloadManagerNotification() - , mDownloaderRunFlag(true) - , mDownloadId(DOWNLOADER_DOWNLOAD_ID_START) - , mDownloadPath(DOWNLOADER_DEFAULT_PATH_LOCATION) - , mCurrentservice(nullptr) - { - LOGINFO("DM: ctor DownloadManagerImplementation: %p", this); - mHttpClient = std::unique_ptr(new DownloadManagerHttpClient); - } - - DownloadManagerImplementation::~DownloadManagerImplementation() - { - LOGINFO("DM: dtor DownloadManagerImplementation: %p", this); - - std::list::iterator itDownloader(mDownloadManagerNotification.begin()); - { - while (itDownloader != mDownloadManagerNotification.end()) - { - (*itDownloader)->Release(); - itDownloader++; - } - } - mDownloadManagerNotification.clear(); - } - - Core::hresult DownloadManagerImplementation::Register(Exchange::IDownloadManager::INotification* notification) - { - LOGINFO("entry"); - ASSERT(notification != nullptr); - - mAdminLock.Lock(); - ASSERT(std::find(mDownloadManagerNotification.begin(), mDownloadManagerNotification.end(), notification) == mDownloadManagerNotification.end()); - if (std::find(mDownloadManagerNotification.begin(), mDownloadManagerNotification.end(), notification) == mDownloadManagerNotification.end()) - { - mDownloadManagerNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - LOGINFO("exit"); - - return Core::ERROR_NONE; - } - - Core::hresult DownloadManagerImplementation::Unregister(Exchange::IDownloadManager::INotification* notification) - { - LOGINFO(); - ASSERT(notification != nullptr); - Core::hresult result = Core::ERROR_NONE; - - /* Remove the notification from the list */ - mAdminLock.Lock(); - auto item = std::find(mDownloadManagerNotification.begin(), mDownloadManagerNotification.end(), notification); - if (item != mDownloadManagerNotification.end()) - { - notification->Release(); - mDownloadManagerNotification.erase(item); - } - else - { - LOGERR("DM: Failed to unregister - notification not found!"); - result = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Initialize(PluginHost::IShell* service) - { - Core::hresult result = Core::ERROR_NONE; - LOGINFO("entry"); - - if (service != nullptr) - { - mCurrentservice = service; - mCurrentservice->AddRef(); - - LOGINFO("DM: ConfigLine=%s", service->ConfigLine().c_str()); - DownloadManagerImplementation::Configuration config; - config.FromString(service->ConfigLine()); - - if (config.downloadDir.IsSet() == true) - { - mDownloadPath = config.downloadDir; - } - if (config.downloadId.IsSet() == true) - { - mDownloadId = static_cast(config.downloadId.Value()); - } - - int rc = mkdir(mDownloadPath.c_str(), 0777); - if (rc != 0 && errno != EEXIST) - { - LOGERR("DM: Failed to create Download Path '%s' rc: %d errno=%d", mDownloadPath.c_str(), rc, errno); - result = Core::ERROR_GENERAL; - } - else - { - LOGINFO("DM: Download path ready at '%s'", mDownloadPath.c_str()); - mDownloadThreadPtr = std::unique_ptr(new std::thread(&DownloadManagerImplementation::downloaderRoutine, this, 1)); - } - } - else - { - LOGERR("DM: Initialization failed - service is null!"); - result = Core::ERROR_GENERAL; - } - - LOGINFO("exit"); - return result; - } - - Core::hresult DownloadManagerImplementation::Deinitialize(PluginHost::IShell* service) - { - Core::hresult result = Core::ERROR_NONE; - LOGINFO(); - - /* Stop the downloader thread */ - mDownloaderRunFlag = false; - mDownloadThreadCV.notify_one(); - if (mDownloadThreadPtr && mDownloadThreadPtr->joinable()) - { - mDownloadThreadPtr->join(); - mDownloadThreadPtr.reset(); - } - - /* Clear download queues */ - { - std::lock_guard lock(mQueueMutex); - /* Clear priority queue */ - while (!mPriorityDownloadQueue.empty()) - { - mPriorityDownloadQueue.pop(); - } - - /* Clear regular queue */ - while (!mRegularDownloadQueue.empty()) - { - mRegularDownloadQueue.pop(); - } - } - - mCurrentservice->Release(); - mCurrentservice = nullptr; - - return result; - } - - // IDownloadManager methods - Core::hresult DownloadManagerImplementation::Download(const string& url, - const Exchange::IDownloadManager::Options &options, - string &downloadId) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!mCurrentservice->SubSystems()->IsActive(PluginHost::ISubSystem::INTERNET)) - { - LOGERR("DM: Download failed - no internet! url=%s priority=%d retries=%u rateLimit=%u", - url.c_str(), options.priority, options.retries, options.rateLimit); - result = Core::ERROR_UNAVAILABLE; - } - else if (url.empty()) - { - LOGERR("DM: Download failed - empty URL! priority=%d retries=%u rateLimit=%u", - options.priority, options.retries, options.rateLimit); - } - else - { - std::lock_guard lock(mQueueMutex); - std::string downloadIdStr = std::to_string(++mDownloadId); - DownloadInfoPtr newDownload = std::make_shared(url, downloadIdStr, options.priority, options.retries, options.rateLimit); - if (newDownload != nullptr) - { - std::string filename = mDownloadPath + "package" + newDownload->getId(); - newDownload->setFileLocator(filename); - - /* Check the priority download request */ - if (options.priority) - { - /* Added to priority queue download */ - mPriorityDownloadQueue.push(newDownload); - } - else - { - /* Added to regular queue download */ - mRegularDownloadQueue.push(newDownload); - } - mDownloadThreadCV.notify_one(); - LOGINFO("DM: Download Request: id=%s url=%s priority=%d retries=%u rateLimit=%u", - newDownload->getId().c_str(), newDownload->getUrl().c_str(), - newDownload->getPriority(), newDownload->getRetries(), - newDownload->getRateLimit()); - - /* Returning queued download id */ - downloadId = newDownload->getId(); - result = Core::ERROR_NONE; - } - else - { - LOGERR("DM: Failed to create new download - url=%s priority=%d retries=%u rateLimit=%u", - url.c_str(), options.priority, options.retries, options.rateLimit); - } - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Pause(const string &downloadId) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!downloadId.empty() && (mCurrentDownload.get() != nullptr) && mHttpClient) - { - if (downloadId.compare(mCurrentDownload->getId()) == 0) - { - mHttpClient->pause(); - LOGINFO("DM: downloadId %s paused", downloadId.c_str()); - result = Core::ERROR_NONE; - } - else - { - LOGWARN("DM: Pause failed - ID mismatch! Requested=%s, Active=%s", - downloadId.c_str(), mCurrentDownload->getId().c_str()); - result = Core::ERROR_UNKNOWN_KEY; - } - } - else - { - LOGERR("DM: Pause failed - downloadId=%s mCurrentDownload=%p mHttpClient=%p", - downloadId.c_str(), mCurrentDownload.get(), mHttpClient.get()); - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Resume(const string &downloadId) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!downloadId.empty() && (mCurrentDownload.get() != nullptr) && mHttpClient) - { - if (downloadId.compare(mCurrentDownload->getId()) == 0) - { - mHttpClient->resume(); - LOGINFO("DM: downloadId %s resumed", downloadId.c_str()); - result = Core::ERROR_NONE; - } - else - { - LOGWARN("DM: Resume failed - ID mismatch! Requested=%s, Active=%s", - downloadId.c_str(), mCurrentDownload->getId().c_str()); - result = Core::ERROR_UNKNOWN_KEY; - } - } - else - { - LOGERR("DM: Resume failed - downloadId=%s mCurrentDownload=%p mHttpClient=%p", - downloadId.c_str(), mCurrentDownload.get(), mHttpClient.get()); - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Cancel(const string &downloadId) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!downloadId.empty() && (mCurrentDownload.get() != nullptr) && mHttpClient) - { - if (downloadId.compare(mCurrentDownload->getId()) == 0) - { - mCurrentDownload->cancel(); - mHttpClient->cancel(); - LOGINFO("DM: downloadId %s cancelled", downloadId.c_str()); - result = Core::ERROR_NONE; - } - else - { - LOGWARN("DM: Cancel failed - ID mismatch! Requested=%s, Active=%s", - downloadId.c_str(), mCurrentDownload->getId().c_str()); - result = Core::ERROR_UNKNOWN_KEY; - } - } - else - { - LOGERR("DM: Cancel failed - downloadId=%s mCurrentDownload=%p mHttpClient=%p", - downloadId.c_str(), mCurrentDownload.get(), mHttpClient.get()); - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Delete(const string &fileLocator) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!fileLocator.empty() && (mCurrentDownload.get() != nullptr) && \ - (fileLocator.compare(mCurrentDownload->getFileLocator()) == 0)) - { - LOGWARN("DM: fileLocator %s download is in-progress", fileLocator.c_str()); - } - else - { - if (remove(fileLocator.c_str()) == 0) - { - LOGINFO("DM: fileLocator %s Deleted", fileLocator.c_str()); - result = Core::ERROR_NONE; - } - else - { - LOGERR("DM: fileLocator '%s' delete failed", fileLocator.c_str()); - } - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::Progress(const string &downloadId, uint8_t &percent) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!downloadId.empty() && (mCurrentDownload.get() != nullptr) && mHttpClient) - { - if (downloadId.compare(mCurrentDownload->getId()) == 0) - { - percent = mHttpClient->getProgress(); - LOGINFO("DM: Download Progress percent %u", percent); - result = Core::ERROR_NONE; - } - else - { - result = Core::ERROR_UNKNOWN_KEY; - } - } - else - { - LOGERR("DM: Progress failed - downloadId=%s mCurrentDownload=%p mHttpClient=%p", - downloadId.c_str(), mCurrentDownload.get(), mHttpClient.get()); - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult DownloadManagerImplementation::GetStorageDetails(uint32_t "aKB, uint32_t &usedKB) - { - Core::hresult result = Core::ERROR_NONE; - /* TODO: Stub - behaves the same as the existing package manager for now */ - return result; - } - - Core::hresult DownloadManagerImplementation::RateLimit(const string &downloadId, const uint32_t &limit) - { - Core::hresult result = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (!downloadId.empty() && (mCurrentDownload.get() != nullptr) && mHttpClient) - { - if (downloadId.compare(mCurrentDownload->getId()) == 0) - { - LOGINFO("DM: downloadId='%s' limit=%u", downloadId.c_str(), limit); - mCurrentDownload->setRateLimit(limit); - mHttpClient->setRateLimit(limit); - result = Core::ERROR_NONE; - } - else - { - LOGWARN("DM: '%s' download is not active - unable to set rate limit=%u!", downloadId.c_str(), limit); - result = Core::ERROR_UNKNOWN_KEY; - } - } - else - { - LOGERR("DM: Set RateLimit Failed - mCurrentDownload=%p", mCurrentDownload.get()); - } - mAdminLock.Unlock(); - - return result; - } - - void DownloadManagerImplementation::downloaderRoutine(int waitTime) - { - while (mDownloaderRunFlag) - { - DownloadInfoPtr downloadRequest = pickDownloadJob(); - while (downloadRequest == nullptr && mDownloaderRunFlag) - { - LOGDBG("DM: Waiting for download request..."); - std::unique_lock lock(mQueueMutex); - mDownloadThreadCV.wait(lock); - lock.unlock(); - - downloadRequest = pickDownloadJob(); - } - - if (false == mDownloaderRunFlag) - { - LOGINFO("DM: Downloader is shutting down - exiting thread!"); - break; - } - - if (!downloadRequest) - { - LOGWARN("DM: No download request available - continuing loop!"); - continue; - } - - DownloadManagerHttpClient::Status status = DownloadManagerHttpClient::Status::Success; - int attemptCount = 0; - - LOGINFO("DM: Starting downloadId=%s url=%s file=%s retries=%d rateLimit=%u", - downloadRequest->getId().c_str(), downloadRequest->getUrl().c_str(), - downloadRequest->getFileLocator().c_str(), downloadRequest->getRetries(), - downloadRequest->getRateLimit()); - - for (int i = 0; i < downloadRequest->getRetries(); ++i) - { - attemptCount = i + 1; - if (i > 0) - { - int retryWaitTime = nextRetryDuration(waitTime); - LOGDBG("DM: Retry %d/%d: Waiting %d seconds before retrying...", - attemptCount, downloadRequest->getRetries(), retryWaitTime); - std::this_thread::sleep_for(std::chrono::seconds(retryWaitTime)); - - if (downloadRequest->cancelled()) - { - LOGINFO("DM: Download cancelled: id=%s !", downloadRequest->getId().c_str()); - break; - } - } - - LOGDBG("DM: Attempting download (%d/%d): id=%s url=%s file=%s rateLimit=%u", - attemptCount, downloadRequest->getRetries(), - downloadRequest->getId().c_str(), - downloadRequest->getUrl().c_str(), - downloadRequest->getFileLocator().c_str(), - downloadRequest->getRateLimit()); - - auto begin = std::chrono::steady_clock::now(); - status = mHttpClient->downloadFile(downloadRequest->getUrl(), - downloadRequest->getFileLocator(), - downloadRequest->getRateLimit()); - auto end = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(end - begin).count(); - long httpCode = mHttpClient->getStatusCode(); - if (status == DownloadManagerHttpClient::Status::Success) - { - LOGINFO("DM: Download succeeded (took %lldms): id=%s url=%s file=%s retries=%d rateLimit=%u http_code=%ld", - elapsed, downloadRequest->getId().c_str(), downloadRequest->getUrl().c_str(), - downloadRequest->getFileLocator().c_str(), downloadRequest->getRetries(), - downloadRequest->getRateLimit(), httpCode); - break; - } - - if (httpCode == 404) - { - LOGERR("DM: Download file not found (404) - id=%s url=%s status=%d", - downloadRequest->getId().c_str(), downloadRequest->getUrl().c_str(), status); - status = DownloadManagerHttpClient::Status::HttpError; - break; - } - - LOGDBG("DM: Attempt download (%d/%d): status=%d http_code=%ld elapsed=%lld ms", - attemptCount, downloadRequest->getRetries(), status, httpCode, elapsed); - } - - if (status != DownloadManagerHttpClient::Status::Success) - { - LOGERR("DM: Download failed %d/%d: id=%s status=%d", - attemptCount, downloadRequest->getRetries(), downloadRequest->getId().c_str(), status); - } - - DownloadReason reason = static_cast(DOWNLOAD_REASON_NONE); - switch (status) - { - case DownloadManagerHttpClient::Status::DiskError: - reason = DownloadReason::DISK_PERSISTENCE_FAILURE; - LOGERR("DM: Download failed due to disk error: id=%s", downloadRequest->getId().c_str()); - break; - - case DownloadManagerHttpClient::Status::HttpError: - reason = DownloadReason::DOWNLOAD_FAILURE; - LOGERR("DM: Download failed due to HTTP error: id=%s", downloadRequest->getId().c_str()); - break; - - default: - break; /* Do nothing */ - } - - notifyDownloadStatus(downloadRequest->getId(), downloadRequest->getFileLocator(), reason); - mCurrentDownload.reset(); - } - LOGINFO("DM: Downloader thread exiting!"); - } - - void DownloadManagerImplementation::notifyDownloadStatus(const string& id, const string& locator, const DownloadReason reason) - { - JsonArray list = JsonArray(); - JsonObject obj; - obj["downloadId"] = id; - obj["fileLocator"] = locator; - if (reason != (DownloadReason)DOWNLOAD_REASON_NONE) - { - obj["failReason"] = getDownloadReason(reason); - } - list.Add(obj); - std::string jsonstr; - if (!list.ToString(jsonstr)) - { - LOGERR("DM: Failed to stringify JsonArray"); - } - else - { - mAdminLock.Lock(); - LOGDBG("DM: OnAppDownloadStatus event: '%s'", jsonstr.c_str()); - for (auto notification: mDownloadManagerNotification) - { - notification->OnAppDownloadStatus(jsonstr); - } - mAdminLock.Unlock(); - } - } - - DownloadManagerImplementation::DownloadInfoPtr DownloadManagerImplementation::pickDownloadJob(void) - { - std::lock_guard lock(mQueueMutex); - if ((!mPriorityDownloadQueue.empty() || !mRegularDownloadQueue.empty()) && mCurrentDownload == nullptr) - { - if (!mPriorityDownloadQueue.empty()) - { - /* Priority queue download request */ - mCurrentDownload = mPriorityDownloadQueue.front(); - mPriorityDownloadQueue.pop(); - LOGINFO("DM: PriorityQ Job: DownloadId=%s url=%s file=%s rateLimit=%u", - mCurrentDownload->getId().c_str(), mCurrentDownload->getUrl().c_str(), - mCurrentDownload->getFileLocator().c_str(), mCurrentDownload->getRateLimit()); - } - else - { - /* Regular queue download request */ - if (!mRegularDownloadQueue.empty()) - { - mCurrentDownload = mRegularDownloadQueue.front(); - mRegularDownloadQueue.pop(); - LOGINFO("DM: RegularQ Job: DownloadId=%s url=%s file=%s rateLimit=%u", - mCurrentDownload->getId().c_str(), mCurrentDownload->getUrl().c_str(), - mCurrentDownload->getFileLocator().c_str(), mCurrentDownload->getRateLimit()); - } - } - } - return mCurrentDownload; - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/DownloadManager/DownloadManagerImplementation.h b/DownloadManager/DownloadManagerImplementation.h deleted file mode 100755 index 6ade5f0..0000000 --- a/DownloadManager/DownloadManagerImplementation.h +++ /dev/null @@ -1,175 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -#include "Module.h" -#include "UtilsLogging.h" -#include - -#include "DownloadManagerHttpClient.h" - -#define DOWNLOAD_REASON_NONE (0xFF) - -namespace WPEFramework { -namespace Plugin { - typedef Exchange::IDownloadManager::FailReason DownloadReason; - - class DownloadManagerImplementation - : public Exchange::IDownloadManager - { - class Configuration : public Core::JSON::Container { - public: - Configuration() - : Core::JSON::Container() - , downloadDir() - , downloadId() - { - Add(_T("downloadDir"), &downloadDir); // - Add(_T("downloadId"), &downloadId); // - } - ~Configuration() = default; - - Configuration(Configuration&&) = delete; - Configuration(const Configuration&) = delete; - Configuration& operator=(Configuration&&) = delete; - Configuration& operator=(const Configuration&) = delete; - - public: - Core::JSON::String downloadDir; - Core::JSON::DecUInt32 downloadId; - }; - - class DownloadInfo { - const unsigned MIN_RETRIES = 2; - public: - DownloadInfo(const string& url, const string& id, bool priority, uint8_t retries, long limit) - : id(id) - , url(url) - , priority(priority) - , retries(retries ? retries : MIN_RETRIES) - , rateLimit(limit) - , isCancelled(false) - { - } - - string getId() { return id; } - string getUrl() { return url; } - bool getPriority() { return priority; } - uint8_t getRetries() { return retries; } - void setRateLimit(uint32_t limit) { rateLimit = limit; } - uint32_t getRateLimit() { return rateLimit; } - string getFileLocator() { return fileLocator; } - void setFileLocator(string &locator) { fileLocator = locator; } - void cancel() { isCancelled = true; } - bool cancelled() { return isCancelled; } - - private: - string id; - string url; - bool priority; - uint8_t retries; - uint32_t rateLimit; - string fileLocator; - bool isCancelled; - }; - - typedef std::shared_ptr DownloadInfoPtr; - typedef std::queue DownloadQueue; - - public: - DownloadManagerImplementation(); - virtual ~DownloadManagerImplementation(); - - // IDownloadManager methods - Core::hresult Download(const string &url, const Exchange::IDownloadManager::Options &options, string &downloadId) override; - Core::hresult Pause(const string &downloadId) override; - Core::hresult Resume(const string &downloadId) override; - Core::hresult Cancel(const string &downloadId) override; - Core::hresult Delete(const string &fileLocator) override; - Core::hresult Progress(const string &downloadId, uint8_t &percent); - Core::hresult GetStorageDetails(uint32_t "aKB, uint32_t &usedKB); - Core::hresult RateLimit(const string &downloadId, const uint32_t &limit); - - Core::hresult Register(Exchange::IDownloadManager::INotification* notification) override; - Core::hresult Unregister(Exchange::IDownloadManager::INotification* notification) override; - - Core::hresult Initialize(PluginHost::IShell* service) override; - Core::hresult Deinitialize(PluginHost::IShell* service) override; - - BEGIN_INTERFACE_MAP(DownloadManagerImplementation) - INTERFACE_ENTRY(Exchange::IDownloadManager) - END_INTERFACE_MAP - - private: - - void downloaderRoutine(int waitTime); - void notifyDownloadStatus(const string& id, const string& locator, const DownloadReason status); - - DownloadInfoPtr pickDownloadJob(void); - int nextRetryDuration(int n) { - const double goldenRatio = (1 + std::sqrt(5)) / 2.0; - double next = n * goldenRatio; - return static_cast(std::round(next)); - } - - string getDownloadReason(DownloadReason reason) { - switch (reason) - { - case DownloadReason::DISK_PERSISTENCE_FAILURE: - return "DISK_PERSISTENCE_FAILURE"; - - case DownloadReason::DOWNLOAD_FAILURE: - return "DOWNLOAD_FAILURE"; - - default: - return ""; - } - } - - private: - mutable Core::CriticalSection mAdminLock; - std::list mDownloadManagerNotification; - std::unique_ptr mHttpClient; - - mutable std::mutex mQueueMutex; - std::condition_variable mDownloadThreadCV; - std::unique_ptr mDownloadThreadPtr; - bool mDownloaderRunFlag; - DownloadInfoPtr mCurrentDownload; - - uint32_t mDownloadId; - DownloadQueue mPriorityDownloadQueue; - DownloadQueue mRegularDownloadQueue; - std::string mDownloadPath; - - PluginHost::IShell* mCurrentservice; - }; -} // namespace Plugin -} // namespace WPEFramework - diff --git a/DownloadManager/Module.cpp b/DownloadManager/Module.cpp deleted file mode 100755 index a05f066..0000000 --- a/DownloadManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/DownloadManager/Module.h b/DownloadManager/Module.h deleted file mode 100755 index 42af42d..0000000 --- a/DownloadManager/Module.h +++ /dev/null @@ -1,30 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_DownloadManager -#endif - -#include -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/FbSettings/CMakeLists.txt b/FbSettings/CMakeLists.txt deleted file mode 100644 index a3be4b7..0000000 --- a/FbSettings/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME FbSettings) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(VERSION_MAJOR 1) -set(VERSION_MINOR 0) -set(VERSION_PATCH 0) - -add_compile_definitions(FBSETTINGS_MAJOR_VERSION=${VERSION_MAJOR}) -add_compile_definitions(FBSETTINGS_MINOR_VERSION=${VERSION_MINOR}) -add_compile_definitions(FBSETTINGS_PATCH_VERSION=${VERSION_PATCH}) - -set(MODULE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) - -set(PLUGIN_FBSETTINGS_STARTUPORDER "" CACHE STRING "To configure startup order of FbSettings plugin") -set(PLUGIN_FBSETTINGS_AUTOSTART "false" CACHE STRING "Automatically start FbSettings plugin") - -message("Setup ${MODULE_NAME} v${MODULE_VERSION}") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) -find_library(NMPROXY_LIB NAMES ${NAMESPACE}NetworkManagerProxy PATHS ${CMAKE_SYSROOT}/usr/lib/wpeframework/proxystubs) - -add_library(${MODULE_NAME} SHARED - FbSettings.cpp - Module.cpp) - - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -# To error any missing links -target_link_options(${MODULE_NAME} PRIVATE -Wl,-z,defs) -# To error any warnings -add_compile_options(-Wall -Werror) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/FbSettings/FbSettings.conf.in b/FbSettings/FbSettings.conf.in deleted file mode 100755 index 2d58392..0000000 --- a/FbSettings/FbSettings.conf.in +++ /dev/null @@ -1,5 +0,0 @@ -autostart = "@PLUGIN_FBSETTINGS_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.FbSettings" -startuporder = "@PLUGIN_FBSETTINGS_STARTUPORDER@" - diff --git a/FbSettings/FbSettings.config b/FbSettings/FbSettings.config deleted file mode 100755 index ec79c7e..0000000 --- a/FbSettings/FbSettings.config +++ /dev/null @@ -1,15 +0,0 @@ -set(autostart ${PLUGIN_FBSETTINGS_AUTOSTART}) - -if(PLUGIN_FBSETTINGS_STARTUPORDER) -set (startuporder ${PLUGIN_FBSETTINGS_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_FBSETTINGS_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) - diff --git a/FbSettings/FbSettings.cpp b/FbSettings/FbSettings.cpp deleted file mode 100644 index 8f1f9ff..0000000 --- a/FbSettings/FbSettings.cpp +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "FbSettings.h" -#include -#include "StringUtils.h" -#include "UtilsFirebolt.h" - - -#define API_VERSION_NUMBER_MAJOR FBSETTINGS_MAJOR_VERSION -#define API_VERSION_NUMBER_MINOR FBSETTINGS_MINOR_VERSION -#define API_VERSION_NUMBER_PATCH FBSETTINGS_PATCH_VERSION - -namespace WPEFramework { - -namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - SERVICE_REGISTRATION(FbSettings, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - FbSettings::FbSettings(): mShell(nullptr), mConnectionId(0) - { - SYSLOG(Logging::Startup, (_T("FbSettings Constructor"))); - } - - FbSettings::~FbSettings() - { - SYSLOG(Logging::Shutdown, (string(_T("FbSettings Destructor")))); - } - - /* virtual */ const string FbSettings::Initialize(PluginHost::IShell* service) - { - ASSERT(service != nullptr); - - SYSLOG(Logging::Startup, (_T("FbSettings::Initialize: PID=%u"), getpid())); - - mShell = service; - mShell->AddRef(); - - // Initialize the settings delegate - mDelegate = std::make_shared(); - mDelegate->setShell(mShell); - - return EMPTY_STRING; - } - - /* virtual */ void FbSettings::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Shutdown, (string(_T("FbSettings::Deinitialize")))); - ASSERT(service == mShell); - mConnectionId = 0; - - mDelegate->Cleanup(); - // Clean up the delegate - mDelegate.reset(); - - mShell->Release(); - mShell = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("FbSettings de-initialised")))); - } - - void FbSettings::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) { - - ASSERT(mShell != nullptr); - - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mShell, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - Core::hresult FbSettings::HandleAppEventNotifier(Exchange::IAppNotificationHandler::IEmitter *cb, const string& event /* @in */, - bool listen /* @in */, - bool &status /* @out */) { - LOGTRACE("HandleFireboltNotifier [event=%s listen=%s]", - event.c_str(), listen ? "true" : "false"); - status = true; - Core::IWorkerPool::Instance().Submit(EventRegistrationJob::Create(this, cb, event, listen)); - return Core::ERROR_NONE; - } - - Core::hresult FbSettings::HandleAppGatewayRequest(const Exchange::GatewayContext &context /* @in */, - const string& method /* @in */, - const string &payload /* @in @opaque */, - string& result /*@out @opaque */) - { - LOGTRACE("HandleAppGatewayRequest: method=%s, payload=%s, appId=%s", - method.c_str(), payload.c_str(), context.appId.c_str()); - std::string lowerMethod = StringUtils::toLower(method); - // Route System/Device methods - if (lowerMethod == "device.make") - { - return GetDeviceMake(result); - } - else if (lowerMethod == "device.name") - { - return GetDeviceName(result); - } - else if (lowerMethod == "device.setname") - { - JsonObject params; - if (params.FromString(payload)) - { - string name = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetDeviceName(name), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "device.sku") - { - return GetDeviceSku(result); - } - else if (lowerMethod == "localization.countrycode") - { - return GetCountryCode(result); - } - else if (lowerMethod == "localization.setcountrycode") - { - JsonObject params; - if (params.FromString(payload)) - { - string countryCode = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetCountryCode(countryCode),result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "localization.timezone") - { - return GetTimeZone(result); - } - else if (lowerMethod == "localization.settimezone") - { - JsonObject params; - if (params.FromString(payload)) - { - string timeZone = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetTimeZone(timeZone),result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "secondscreen.friendlyname") - { - return GetSecondScreenFriendlyName(result); - } - else if (lowerMethod == "localization.addadditionalinfo") - { - return ResponseUtils::SetNullResponseForSuccess(AddAdditionalInfo(payload, result), result); - } - - // Route network-related methods - else if (lowerMethod == "device.network") - { - return GetInternetConnectionStatus(result); - } - - // Route voice guidance methods - else if (lowerMethod == "voiceguidance.enabled") - { - return GetVoiceGuidance(result); - } - else if (lowerMethod == "voiceguidance.setenabled") - { - // Parse payload for boolean value - JsonObject params; - if (params.FromString(payload)) - { - bool enabled = params.Get("value").Boolean(); - return ResponseUtils::SetNullResponseForSuccess(SetVoiceGuidance(enabled), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "voiceguidance.speed" || lowerMethod == "voiceguidance.rate") - { - double speed; - Core::hresult status = GetSpeed(speed); - if (status == Core::ERROR_NONE) - { - std::ostringstream jsonStream; - jsonStream << speed; - result = jsonStream.str(); - } - return status; - } - else if (lowerMethod == "voiceguidance.setspeed" || lowerMethod == "voiceguidance.setrate") - { - JsonObject params; - if (params.FromString(payload)) - { - double speed = params.Get("value").Number(); - return ResponseUtils::SetNullResponseForSuccess(SetSpeed(speed), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "voiceguidance.navigationhints") - { - return GetVoiceGuidanceHints(result); - } - else if (lowerMethod == "voiceguidance.setnavigationhints") - { - JsonObject params; - if (params.FromString(payload)) - { - bool enabled = params.Get("value").Boolean(); - return ResponseUtils::SetNullResponseForSuccess(SetVoiceGuidanceHints(enabled), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "accessibility.voiceguidancesettings") - { - return GetVoiceGuidanceSettings(result); - } - else if (lowerMethod == "accessibility.voiceguidance") - { - return GetVoiceGuidanceSettings(result); - } - - // Route audio description methods - else if (lowerMethod == "accessibility.audiodescriptionsettings") - { - return GetAudioDescription(result); - } - else if (lowerMethod == "audiodescriptions.enabled") - { - return GetAudioDescriptionsEnabled(result); - } - else if (lowerMethod == "audiodescriptions.setenabled") - { - JsonObject params; - if (params.FromString(payload)) - { - bool enabled = params.Get("value").Boolean(); - return ResponseUtils::SetNullResponseForSuccess(SetAudioDescriptionsEnabled(enabled), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - - // Route accessibility methods - else if (lowerMethod == "accessibility.highcontrastui") - { - return GetHighContrast(result); - } - - // Route closed captions methods - else if (lowerMethod == "closedcaptions.enabled") - { - return GetCaptions(result); - } - else if (lowerMethod == "closedcaptions.setenabled") - { - JsonObject params; - if (params.FromString(payload)) - { - bool enabled = params.Get("value").Boolean(); - return ResponseUtils::SetNullResponseForSuccess(SetCaptions(enabled), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "closedcaptions.preferredlanguages") - { - return GetPreferredCaptionsLanguages(result); - } - else if (lowerMethod == "closedcaptions.setpreferredlanguages") - { - JsonObject params; - if (params.FromString(payload)) - { - string languages = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetPreferredCaptionsLanguages(languages), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "accessibility.closedcaptions") - { - return GetClosedCaptionsSettings(result); - } - else if (lowerMethod == "accessibility.closedcaptionssettings") - { - return GetClosedCaptionsSettings(result); - } - - // Route localization methods - else if (lowerMethod == "localization.language") - { - return GetPresentationLanguage(result); - } - else if (lowerMethod == "localization.locale") - { - return GetLocale(result); - } - else if (lowerMethod == "localization.setlocale") - { - JsonObject params; - if (params.FromString(payload)) - { - string locale = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetLocale(locale), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "localization.preferredaudiolanguages") - { - return GetPreferredAudioLanguages(result); - } - else if (lowerMethod == "localization.setpreferredaudiolanguages") - { - JsonObject params; - if (params.FromString(payload)) - { - string languages = params.Get("value").String(); - return ResponseUtils::SetNullResponseForSuccess(SetPreferredAudioLanguages(languages), result); - } - result = "{\"error\":\"Invalid payload\"}"; - return Core::ERROR_BAD_REQUEST; - } - else if (lowerMethod == "device.version") - { - return GetFirmwareVersion(result); - } - else if (lowerMethod == "device.screenresolution") - { - return GetScreenResolution(result); - } - else if (lowerMethod == "device.videoresolution") - { - return GetVideoResolution(result); - } - else if (lowerMethod == "device.hdcp") - { - return GetHdcp(result); - } - else if (lowerMethod == "device.hdr") - { - return GetHdr(result); - } - else if (lowerMethod == "device.audio") - { - return GetAudio(result); - } - - // If method not found, return error - ErrorUtils::NotSupported(result); - LOGERR("Unsupported method: %s", method.c_str()); - return Core::ERROR_UNKNOWN_KEY; - } - - Core::hresult FbSettings::SetName(const string &value /* @in */, string &result) - { - result = "null"; // TBA - return Core::ERROR_NONE; - } - - Core::hresult FbSettings::AddAdditionalInfo(const string &value /* @in @opaque */, string &result) - { - result = "null"; // TBA - return Core::ERROR_NONE; - } - // Delegated alias methods - - Core::hresult FbSettings::GetDeviceMake(string &make) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetDeviceMake(make); - } - - Core::hresult FbSettings::GetDeviceName(string &name) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetDeviceName(name); - } - - Core::hresult FbSettings::SetDeviceName(const string name) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->SetDeviceName(name); - } - - Core::hresult FbSettings::GetDeviceSku(string &sku) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetDeviceSku(sku); - } - - Core::hresult FbSettings::GetCountryCode(string &countryCode) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetCountryCode(countryCode); - } - - Core::hresult FbSettings::SetCountryCode(const string countryCode) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->SetCountryCode(countryCode); - } - - Core::hresult FbSettings::GetTimeZone(string &timeZone) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetTimeZone(timeZone); - } - - Core::hresult FbSettings::SetTimeZone(const string timeZone) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->SetTimeZone(timeZone); - } - - Core::hresult FbSettings::GetSecondScreenFriendlyName(string &name) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetSecondScreenFriendlyName(name); - } - - // UserSettings APIs - Core::hresult FbSettings::GetVoiceGuidance(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get voiceguidance state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get voiceguidance state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetVoiceGuidance(result); - } - - Core::hresult FbSettings::GetAudioDescription(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get audio description settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get audio description settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetAudioDescription(result); - } - - Core::hresult FbSettings::GetAudioDescriptionsEnabled(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get audio descriptions enabled\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get audio descriptions enabled\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetAudioDescriptionsEnabled(result); - } - - Core::hresult FbSettings::GetHighContrast(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get high contrast state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get high contrast state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetHighContrast(result); - } - - Core::hresult FbSettings::GetCaptions(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get captions state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get captions state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetCaptions(result); - } - - Core::hresult FbSettings::GetPresentationLanguage(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldn't get language\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldn't get language\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetPresentationLanguage(result); - } - - Core::hresult FbSettings::GetLocale(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldn't get locale\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldn't get locale\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetLocale(result); - } - - Core::hresult FbSettings::SetLocale(const string &locale) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetLocale(locale); - } - - Core::hresult FbSettings::GetPreferredAudioLanguages(string &result) - { - if (!mDelegate) - { - result = "[]"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "[]"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetPreferredAudioLanguages(result); - } - - Core::hresult FbSettings::GetPreferredCaptionsLanguages(string &result) - { - if (!mDelegate) - { - result = "[\"eng\"]"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "[\"eng\"]"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetPreferredCaptionsLanguages(result); - } - - Core::hresult FbSettings::SetPreferredAudioLanguages(const string &languages) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetPreferredAudioLanguages(languages); - } - - Core::hresult FbSettings::SetPreferredCaptionsLanguages(const string &preferredLanguages) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetPreferredCaptionsLanguages(preferredLanguages); - } - - Core::hresult FbSettings::SetVoiceGuidance(const bool enabled) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetVoiceGuidance(enabled); - } - - Core::hresult FbSettings::SetAudioDescriptionsEnabled(const bool enabled) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetAudioDescriptionsEnabled(enabled); - } - - Core::hresult FbSettings::SetCaptions(const bool enabled) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetCaptions(enabled); - } - - Core::hresult FbSettings::SetSpeed(const double speed) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - // Transform the speed using vg_speed_firebolt2thunder function logic: - // (if $speed == 2 then 10 elif $speed >= 1.67 then 1.38 elif $speed >= 1.33 then 1.19 elif $speed >= 1 then 1 else 0.1 end) - double transformedRate; - if (speed == 2.0) - { - transformedRate = 10.0; - } - else if (speed >= 1.67) - { - transformedRate = 1.38; - } - else if (speed >= 1.33) - { - transformedRate = 1.19; - } - else if (speed >= 1.0) - { - transformedRate = 1.0; - } - else - { - transformedRate = 0.1; - } - - LOGINFO("SetSpeed: transforming speed %f to rate %f", speed, transformedRate); - - return userSettingsDelegate->SetVoiceGuidanceRate(transformedRate); - } - - Core::hresult FbSettings::GetSpeed(double &speed) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - double rate; - Core::hresult result = userSettingsDelegate->GetVoiceGuidanceRate(rate); - - if (result != Core::ERROR_NONE) - { - LOGERR("Failed to get voice guidance rate"); - return result; - } - - // Transform the rate using vg_speed_thunder2firebolt function logic: - // (if $speed >= 1.56 then 2 elif $speed >= 1.38 then 1.67 elif $speed >= 1.19 then 1.33 elif $speed >= 1 then 1 else 0.5 end) - if (rate >= 1.56) - { - speed = 2.0; - } - else if (rate >= 1.38) - { - speed = 1.67; - } - else if (rate >= 1.19) - { - speed = 1.33; - } - else if (rate >= 1.0) - { - speed = 1.0; - } - else - { - speed = 0.5; - } - - LOGINFO("GetSpeed: transforming rate %f to speed %f", rate, speed); - - return Core::ERROR_NONE; - } - - Core::hresult FbSettings::GetVoiceGuidanceHints(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldnt get navigationHints\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldnt get navigationHints\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->GetVoiceGuidanceHints(result); - } - - Core::hresult FbSettings::SetVoiceGuidanceHints(const bool enabled) - { - if (!mDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - return Core::ERROR_UNAVAILABLE; - } - - return userSettingsDelegate->SetVoiceGuidanceHints(enabled); - } - - Core::hresult FbSettings::GetVoiceGuidanceSettings(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldn't get voice guidance settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldn't get voice guidance settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - // Get voice guidance enabled state - string enabledResult; - Core::hresult enabledStatus = userSettingsDelegate->GetVoiceGuidance(enabledResult); - if (enabledStatus != Core::ERROR_NONE) - { - result = "{\"error\":\"couldn't get voiceguidance enabled state\"}"; - return enabledStatus; - } - - // Get voice guidance rate (speed) - double rate; - Core::hresult rateStatus = userSettingsDelegate->GetVoiceGuidanceRate(rate); - if (rateStatus != Core::ERROR_NONE) - { - result = "{\"error\":\"couldn't get voiceguidance rate\"}"; - return rateStatus; - } - - // Get navigation hints - string hintsResult; - Core::hresult hintsStatus = userSettingsDelegate->GetVoiceGuidanceHints(hintsResult); - if (hintsStatus != Core::ERROR_NONE) - { - result = "{\"error\":\"couldn't get voiceguidance hints\"}"; - return hintsStatus; - } - - // Construct the combined JSON response - // Format: {"enabled": , "speed": , "rate": , "navigationHints": } - std::ostringstream jsonStream; - jsonStream << "{\"enabled\": " << enabledResult - << ", \"speed\": " << rate - << ", \"rate\": " << rate - << ", \"navigationHints\": " << hintsResult << "}"; - - result = jsonStream.str(); - - return Core::ERROR_NONE; - } - - Core::hresult FbSettings::GetClosedCaptionsSettings(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldn't get closed captions settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto userSettingsDelegate = mDelegate->getUserSettings(); - if (!userSettingsDelegate) - { - result = "{\"error\":\"couldn't get closed captions settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - // Get closed captions enabled state - string enabledResult; - Core::hresult enabledStatus = userSettingsDelegate->GetCaptions(enabledResult); - if (enabledStatus != Core::ERROR_NONE) - { - result = "{\"error\":\"couldn't get closed captions enabled state\"}"; - return enabledStatus; - } - - // Get preferred captions languages - string languagesResult; - Core::hresult languagesStatus = userSettingsDelegate->GetPreferredCaptionsLanguages(languagesResult); - if (languagesStatus != Core::ERROR_NONE) - { - result = "{\"error\":\"couldn't get preferred captions languages\"}"; - return languagesStatus; - } - - // Construct the combined JSON response - // Format: {"enabled": , "preferredLanguages": , "styles": {}} - std::ostringstream jsonStream; - jsonStream << "{\"enabled\": " << enabledResult - << ", \"preferredLanguages\": " << languagesResult - << ", \"styles\": {}}"; - - result = jsonStream.str(); - - return Core::ERROR_NONE; - } - - Core::hresult FbSettings::GetInternetConnectionStatus(string &result) - { - if (!mDelegate) - { - result = "{\"error\":\"couldn't get internet connection status\"}"; - return Core::ERROR_UNAVAILABLE; - } - - auto networkDelegate = mDelegate->getNetworkDelegate(); - if (!networkDelegate) - { - result = "{\"error\":\"couldn't get internet connection status\"}"; - return Core::ERROR_UNAVAILABLE; - } - - return networkDelegate->GetInternetConnectionStatus(result); - } - - Core::hresult FbSettings::GetFirmwareVersion(string &result /* @out */) - { - if (!mDelegate) - return Core::ERROR_UNAVAILABLE; - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) - return Core::ERROR_UNAVAILABLE; - return systemDelegate->GetFirmwareVersion(result); - } - - // Core::hresult FbSettings::GetScreenResolution(string &result /* out */) { - // result = R"([1920,1080])"; - // return Core::ERROR_NONE; - // } - - // Core::hresult FbSettings::GetVideoResolution(string &result /* out */) { - // result = R"([1920,1080])"; - // return Core::ERROR_NONE; - // } - - Core::hresult FbSettings::GetScreenResolution(string &result) - { - LOGINFO("GetScreenResolution FbSettings"); - if (!mDelegate) { - result = "[1920,1080]"; - return Core::ERROR_UNAVAILABLE; - } - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) { - result = "[1920,1080]"; - return Core::ERROR_UNAVAILABLE; - } - return systemDelegate->GetScreenResolution(result); - } - - Core::hresult FbSettings::GetVideoResolution(string &result) - { - LOGINFO("GetVideoResolution FbSettings"); - if (!mDelegate) { - result = "[1920,1080]"; - return Core::ERROR_UNAVAILABLE; - } - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) { - result = "[1920,1080]"; - return Core::ERROR_UNAVAILABLE; - } - return systemDelegate->GetVideoResolution(result); - } - - Core::hresult FbSettings::GetHdcp(string &result) - { - LOGINFO("GetHdcp FbSettings"); - if (!mDelegate) { - result = "{\"hdcp1.4\":false,\"hdcp2.2\":false}"; - return Core::ERROR_UNAVAILABLE; - } - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) { - result = "{\"hdcp1.4\":false,\"hdcp2.2\":false}"; - return Core::ERROR_UNAVAILABLE; - } - return systemDelegate->GetHdcp(result); - } - - Core::hresult FbSettings::GetHdr(string &result) - { - LOGINFO("GetHdr FbSettings"); - if (!mDelegate) { - result = "{\"hdr10\":false,\"dolbyVision\":false,\"hlg\":false,\"hdr10Plus\":false}"; - return Core::ERROR_UNAVAILABLE; - } - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) { - result = "{\"hdr10\":false,\"dolbyVision\":false,\"hlg\":false,\"hdr10Plus\":false}"; - return Core::ERROR_UNAVAILABLE; - } - return systemDelegate->GetHdr(result); - } - - Core::hresult FbSettings::GetAudio(string &result) - { - LOGINFO("GetAudio FbSettings"); - if (!mDelegate) { - result = "{\"stereo\":true,\"dolbyDigital5.1\":false,\"dolbyDigital5.1+\":false,\"dolbyAtmos\":false}"; - return Core::ERROR_UNAVAILABLE; - } - auto systemDelegate = mDelegate->getSystemDelegate(); - if (!systemDelegate) { - result = "{\"stereo\":true,\"dolbyDigital5.1\":false,\"dolbyDigital5.1+\":false,\"dolbyAtmos\":false}"; - return Core::ERROR_UNAVAILABLE; - } - return systemDelegate->GetAudio(result); - } - - -} // namespace Plugin -} // namespace WPEFramework - diff --git a/FbSettings/FbSettings.h b/FbSettings/FbSettings.h deleted file mode 100644 index 74b5565..0000000 --- a/FbSettings/FbSettings.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "UtilsController.h" -#include "delegate/SettingsDelegate.h" - -namespace WPEFramework { - - namespace Plugin { - - - class FbSettings : public PluginHost::IPlugin, Exchange::IAppGatewayRequestHandler, Exchange::IAppNotificationHandler{ - private: - // We do not allow this plugin to be copied !! - FbSettings(const FbSettings&) = delete; - FbSettings& operator=(const FbSettings&) = delete; - - class EXTERNAL EventRegistrationJob : public Core::IDispatch - { - protected: - EventRegistrationJob(FbSettings *parent, - Exchange::IAppNotificationHandler::IEmitter *cb, - const string &event, - const bool listen): mParent(*parent), mCallback(cb), mEvent(event), mListen(listen) { - if (mCallback != nullptr) { - mCallback->AddRef(); - } - } - public: - EventRegistrationJob() = delete; - EventRegistrationJob(const EventRegistrationJob &) = delete; - EventRegistrationJob &operator=(const EventRegistrationJob &) = delete; - ~EventRegistrationJob() - { - if (mCallback != nullptr) { - mCallback->Release(); - mCallback = nullptr; - } - } - - static Core::ProxyType Create(FbSettings *parent, - Exchange::IAppNotificationHandler::IEmitter *cb, const string& event, const bool listen) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, cb, event, listen))); - } - virtual void Dispatch() - { - mParent.mDelegate->HandleAppEventNotifier(mCallback, mEvent, mListen); - } - - private: - FbSettings &mParent; - Exchange::IAppNotificationHandler::IEmitter *mCallback; - const string mEvent; - const bool mListen; - - }; - - - public: - FbSettings(); - virtual ~FbSettings(); - virtual const string Initialize(PluginHost::IShell* shell) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override { return {}; } - - BEGIN_INTERFACE_MAP(FbSettings) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(Exchange::IAppGatewayRequestHandler) - INTERFACE_ENTRY(Exchange::IAppNotificationHandler) - END_INTERFACE_MAP - - public: - virtual Core::hresult HandleAppEventNotifier(Exchange::IAppNotificationHandler::IEmitter *cb /* @in */, - const string& event /* @in */, - bool listen /* @in */, - bool& status /* @out */) override; - - virtual Core::hresult HandleAppGatewayRequest(const Exchange::GatewayContext &context /* @in */, - const string& method /* @in */, - const string &payload /* @in @opaque */, - string& result /*@out @opaque */) override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - // Helper methods for System/Device - called by HandleAppGatewayRequest - Core::hresult GetDeviceMake(string &make /* @out */); - Core::hresult GetDeviceName(string &name /* @out */); - Core::hresult SetDeviceName(const string name /* @in */); - Core::hresult GetDeviceSku(string &sku /* @out */); - Core::hresult GetCountryCode(string &countryCode /* @out */); - Core::hresult SetCountryCode(const string countryCode /* @in */); - Core::hresult GetTimeZone(string &timeZone /* @out */); - Core::hresult SetTimeZone(const string timeZone /* @in */); - Core::hresult GetSecondScreenFriendlyName(string &name /* @out */); - Core::hresult SetName(const string &value /* @in */, string &result /* @out */); - Core::hresult AddAdditionalInfo(const string &value /* @in */, string &result /* @out */); - - // Helper methods for network status - called by HandleAppGatewayRequest - Core::hresult GetInternetConnectionStatus(string &result /* @out */); - - // Helper methods for UserSettings - called by HandleAppGatewayRequest - Core::hresult GetVoiceGuidance(string &result /* @out */); - Core::hresult GetAudioDescription(string &result /* @out */); - Core::hresult GetAudioDescriptionsEnabled(string &result /* @out */); - Core::hresult GetHighContrast(string &result /* @out */); - Core::hresult GetCaptions(string &result /* @out */); - Core::hresult SetVoiceGuidance(const bool enabled /* @in */); - Core::hresult SetAudioDescriptionsEnabled(const bool enabled /* @in */); - Core::hresult SetCaptions(const bool enabled /* @in */); - Core::hresult GetPresentationLanguage(string &result /* @out */); - Core::hresult GetLocale(string &result /* @out */); - Core::hresult SetLocale(const string &locale /* @in */); - Core::hresult GetPreferredAudioLanguages(string &result /* @out */); - Core::hresult GetPreferredCaptionsLanguages(string &result /* @out */); - Core::hresult SetPreferredAudioLanguages(const string &languages /* @in */); - Core::hresult SetPreferredCaptionsLanguages(const string &preferredLanguages /* @in */); - Core::hresult SetSpeed(const double speed /* @in */); - Core::hresult GetSpeed(double &speed /* @out */); - Core::hresult GetVoiceGuidanceHints(string &result /* @out */); - Core::hresult SetVoiceGuidanceHints(const bool enabled /* @in */); - Core::hresult GetVoiceGuidanceSettings(string &result /* @out */); - Core::hresult GetClosedCaptionsSettings(string &result /* @out */); - Core::hresult GetFirmwareVersion(string &result /* @out */); - Core::hresult GetScreenResolution(string &result /* out */); - Core::hresult GetVideoResolution(string &result /* out */); - Core::hresult GetHdcp(string &result /* @out */); - Core::hresult GetHdr(string &result /* @out */); - Core::hresult GetAudio(string &result /* @out */); - - private: - PluginHost::IShell* mShell; - uint32_t mConnectionId; - std::shared_ptr mDelegate; - }; - } // namespace Plugin -} // namespace WPEFramework - diff --git a/FbSettings/Module.cpp b/FbSettings/Module.cpp deleted file mode 100755 index 713d4b1..0000000 --- a/FbSettings/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/FbSettings/Module.h b/FbSettings/Module.h deleted file mode 100755 index 0242984..0000000 --- a/FbSettings/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_FbSettings -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/FbSettings/delegate/NetworkDelegate.h b/FbSettings/delegate/NetworkDelegate.h deleted file mode 100644 index fc6aec3..0000000 --- a/FbSettings/delegate/NetworkDelegate.h +++ /dev/null @@ -1,294 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#pragma once - -#ifndef __NETWORKDELEGATE_H__ -#define __NETWORKDELEGATE_H__ - -#include "StringUtils.h" -#include "BaseEventDelegate.h" -#include -#include "UtilsLogging.h" -#include -#include -#include - -using namespace WPEFramework; - -#define NETWORKMANAGER_CALLSIGN "org.rdk.NetworkManager" - -// Valid network events that can be subscribed to -static const std::set VALID_NETWORK_EVENT = { - "device.onnetworkchanged" -}; - -class NetworkDelegate : public BaseEventDelegate -{ -public: - NetworkDelegate(PluginHost::IShell *shell) - : BaseEventDelegate(), mNetworkManager(nullptr), mShell(shell), mNotificationHandler(*this) - { - } - - ~NetworkDelegate() - { - if (mNetworkManager != nullptr) - { - mNetworkManager->Release(); - mNetworkManager = nullptr; - } - } - - bool HandleSubscription(Exchange::IAppNotificationHandler::IEmitter *cb, const string &event, const bool listen) - { - if (listen) - { - Exchange::INetworkManager *networkManager = GetNetworkManagerInterface(); - if (networkManager == nullptr) - { - LOGERR("NetworkManager interface not available"); - return false; - } - - AddNotification(event, cb); - - if (!mNotificationHandler.GetRegistered()) - { - LOGINFO("Registering for NetworkManager notifications"); - mNetworkManager->Register(&mNotificationHandler); - mNotificationHandler.SetRegistered(true); - return true; - } - else - { - LOGTRACE("Is NetworkManager registered = %s", mNotificationHandler.GetRegistered() ? "true" : "false"); - } - } - else - { - // Not removing the notification subscription for cases where only one event is removed - RemoveNotification(event, cb); - } - return false; - } - - bool HandleEvent(Exchange::IAppNotificationHandler::IEmitter *cb, const string &event, const bool listen, bool ®istrationError) - { - LOGDBG("Checking for handle event"); - // Check if event is present in VALID_NETWORK_EVENT make check case insensitive - if (VALID_NETWORK_EVENT.find(StringUtils::toLower(event)) != VALID_NETWORK_EVENT.end()) - { - // Handle NetworkManager event - registrationError = HandleSubscription(cb, event, listen); - return true; - } - return false; - } - - // Common method to ensure mNetworkManager is available for all APIs - Exchange::INetworkManager *GetNetworkManagerInterface() - { - if (mNetworkManager == nullptr && mShell != nullptr) - { - mNetworkManager = mShell->QueryInterfaceByCallsign(NETWORKMANAGER_CALLSIGN); - if (mNetworkManager == nullptr) - { - LOGERR("Failed to get NetworkManager COM interface"); - } - } - return mNetworkManager; - } - - // PUBLIC_INTERFACE - Core::hresult GetInternetConnectionStatus(std::string &result) - { - /** - * Retrieve the first connected interface from GetAvailableInterfaces - * Transform: Map connected interfaces and return type in lowercase with state - * Transform logic: .result.interfaces| .[] | select(."connected"==true) | - * {type: .interface, state: map_connected(.connected)} | - * .type |= ascii_downcase | [., inputs][0] - */ - LOGINFO("GetInternetConnectionStatus via NetworkManager"); - result.clear(); - - // Get NetworkManager interface - Exchange::INetworkManager *networkManager = GetNetworkManagerInterface(); - if (networkManager == nullptr) - { - LOGERR("NetworkManager interface not available"); - result = "{\"error\":\"NetworkManager not available\"}"; - return Core::ERROR_UNAVAILABLE; - } - - // Get available interfaces - Exchange::INetworkManager::IInterfaceDetailsIterator *interfaces = nullptr; - uint32_t rc = mNetworkManager->GetAvailableInterfaces(interfaces); - - if (rc != Core::ERROR_NONE) - { - LOGERR("GetAvailableInterfaces call failed with error: %u", rc); - result = "{\"error\":\"Failed to get available interfaces\"}"; - return Core::ERROR_GENERAL; - } - - if (interfaces == nullptr) - { - LOGERR("GetAvailableInterfaces returned null iterator"); - result = "{}"; - return Core::ERROR_NONE; - } - - // Iterate through interfaces and find the first connected one - Exchange::INetworkManager::InterfaceDetails iface{}; - bool foundConnected = false; - - while (interfaces->Next(iface)) - { - if (iface.connected) - { - // Get interface type string - map enum to string manually - std::string interfaceType; - switch (iface.type) { - case Exchange::INetworkManager::INTERFACE_TYPE_ETHERNET: - interfaceType = "ethernet"; - break; - case Exchange::INetworkManager::INTERFACE_TYPE_WIFI: - interfaceType = "wifi"; - break; - default: - interfaceType = "unknown"; - break; - } - - // Build the result JSON: {"type": "", "state": "connected"} - std::ostringstream jsonStream; - jsonStream << "{\"type\":\"" << interfaceType - << "\",\"state\":\"connected\"}"; - result = jsonStream.str(); - - LOGINFO("Found connected interface: %s", result.c_str()); - foundConnected = true; - break; - } - } - - // Release the iterator - interfaces->Release(); - - if (!foundConnected) - { - // No connected interface found - result = "{}"; - LOGINFO("No connected interface found"); - } - - return Core::ERROR_NONE; - } - -private: - class NetworkNotificationHandler : public Exchange::INetworkManager::INotification - { - public: - NetworkNotificationHandler(NetworkDelegate &parent) : mParent(parent), registered(false) {} - ~NetworkNotificationHandler() {} - - void onInterfaceStateChange(const Exchange::INetworkManager::InterfaceState state, const string interface) - { - LOGDBG("onInterfaceStateChange: interface=%s, state=%d", interface.c_str(), state); - } - - void onActiveInterfaceChange(const string prevActiveInterface, const string currentActiveInterface) - { - LOGDBG("onActiveInterfaceChange: prev=%s, current=%s", prevActiveInterface.c_str(), currentActiveInterface.c_str()); - } - - void onIPAddressChange(const string interface, const string ipversion, const string ipaddress, const Exchange::INetworkManager::IPStatus status) - { - LOGDBG("onIPAddressChange: interface=%s, ip=%s, status=%d", interface.c_str(), ipaddress.c_str(), status); - } - - void onInternetStatusChange(const Exchange::INetworkManager::InternetStatus prevState, const Exchange::INetworkManager::InternetStatus currState, const string interface) - { - LOGINFO("onInternetStatusChange: prevState=%d, currState=%d, interface=%s", prevState, currState, interface.c_str()); - - // Map internet status to readable strings - auto statusToString = [](Exchange::INetworkManager::InternetStatus status) -> string { - switch (status) { - case Exchange::INetworkManager::INTERNET_FULLY_CONNECTED: return "connected"; - case Exchange::INetworkManager::INTERNET_CAPTIVE_PORTAL: return "captive_portal"; - case Exchange::INetworkManager::INTERNET_LIMITED: return "limited"; - case Exchange::INetworkManager::INTERNET_NOT_AVAILABLE: return "not_available"; - default: return "unknown"; - } - }; - - // Dispatch network change event for internet status changes - std::ostringstream jsonStream; - jsonStream << "{\"network\":{\"state\":\"" << statusToString(currState) - << "\",\"prevState\":\"" << statusToString(prevState) << "\"}}"; - mParent.Dispatch("device.onNetworkChanged", jsonStream.str()); - } - - void onAvailableSSIDs(const string jsonOfScanResults) - { - LOGDBG("onAvailableSSIDs received"); - } - - void onWiFiStateChange(const Exchange::INetworkManager::WiFiState state) - { - LOGDBG("onWiFiStateChange: state=%d", state); - } - - void onWiFiSignalQualityChange(const string ssid, const string strength, const string noise, const string snr, const Exchange::INetworkManager::WiFiSignalQuality quality) - { - LOGDBG("onWiFiSignalQualityChange: ssid=%s", ssid.c_str()); - } - - // Registration management methods - void SetRegistered(bool state) - { - std::lock_guard lock(registerMutex); - registered = state; - } - - bool GetRegistered() - { - std::lock_guard lock(registerMutex); - return registered; - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(Exchange::INetworkManager::INotification) - END_INTERFACE_MAP - - private: - NetworkDelegate &mParent; - bool registered; - std::mutex registerMutex; - }; - - Exchange::INetworkManager *mNetworkManager; - PluginHost::IShell *mShell; - Core::Sink mNotificationHandler; -}; - -#endif // __NETWORKDELEGATE_H__ - diff --git a/FbSettings/delegate/SettingsDelegate.h b/FbSettings/delegate/SettingsDelegate.h deleted file mode 100644 index 02410b7..0000000 --- a/FbSettings/delegate/SettingsDelegate.h +++ /dev/null @@ -1,116 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef __SETTINGSDELEGATE_H__ -#define __SETTINGSDELEGATE_H__ -#include "StringUtils.h" -#include "UserSettingsDelegate.h" -#include "SystemDelegate.h" -#include "NetworkDelegate.h" -#include "UtilsLogging.h" -#include - -#define APP_NOTIFICATIONS_CALLSIGN "org.rdk.AppNotifications" -using namespace WPEFramework; - -class SettingsDelegate { - public: - SettingsDelegate(): userSettings(nullptr), systemDelegate(nullptr), networkDelegate(nullptr) {} - - ~SettingsDelegate() { - userSettings = nullptr; - systemDelegate = nullptr; - networkDelegate = nullptr; - } - - void HandleAppEventNotifier(Exchange::IAppNotificationHandler::IEmitter *cb, const string event, - const bool listen) { - LOGDBG("Passing on HandleAppEventNotifier"); - bool registrationError; - if (userSettings==nullptr || systemDelegate==nullptr || networkDelegate==nullptr) { - LOGERR("Services not available"); - return; - } - - std::vector> delegates = {userSettings, systemDelegate, networkDelegate}; - bool handled = false; - - for (const auto& delegate : delegates) { - if (delegate==nullptr) { - continue; - } - if (delegate->HandleEvent(cb, event, listen, registrationError)) { - handled = true; - break; - } - } - - if (!handled) { - LOGERR("No Matching registrations"); - } - - if (registrationError) { - LOGERR("Error in registering/unregistering for event %s", event.c_str()); - } - } - - void setShell(PluginHost::IShell* shell) { - - ASSERT(shell != nullptr); - LOGDBG("SettingsDelegate::setShell"); - - if (userSettings == nullptr) { - userSettings = std::make_shared(shell); - } - - if (systemDelegate == nullptr) { - systemDelegate = std::make_shared(shell); - } - - if (networkDelegate == nullptr) { - networkDelegate = std::make_shared(shell); - } - } - - void Cleanup() { - systemDelegate.reset(); - userSettings.reset(); - networkDelegate.reset(); - } - - std::shared_ptr getSystemDelegate() const { - return systemDelegate; - } - - std::shared_ptr getUserSettings() { - return userSettings; - } - - std::shared_ptr getNetworkDelegate() const { - return networkDelegate; - } - private: - std::shared_ptr userSettings; - std::shared_ptr systemDelegate; - std::shared_ptr networkDelegate; -}; - -#endif - - diff --git a/FbSettings/delegate/SystemDelegate.h b/FbSettings/delegate/SystemDelegate.h deleted file mode 100644 index b166a31..0000000 --- a/FbSettings/delegate/SystemDelegate.h +++ /dev/null @@ -1,1131 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - -#pragma once - -#include -#include -#include - -#include -#include -#include "UtilsLogging.h" -#include "UtilsJsonrpcDirectLink.h" -#include "UtilsController.h" -#include "BaseEventDelegate.h" -#include - -using namespace WPEFramework; - -// Define a callsign constant to match the AUTHSERVICE_CALLSIGN-style pattern. -#ifndef SYSTEM_CALLSIGN -#define SYSTEM_CALLSIGN "org.rdk.System" -#endif - -#ifndef DISPLAYSETTINGS_CALLSIGN -#define DISPLAYSETTINGS_CALLSIGN "org.rdk.DisplaySettings" -#endif - -#ifndef HDCPPROFILE_CALLSIGN -#define HDCPPROFILE_CALLSIGN "org.rdk.HdcpProfile" -#endif - -class SystemDelegate: public BaseEventDelegate -{ -public: - - // Event names exposed by this delegate (consumer subscriptions may vary in case) - static constexpr const char* EVENT_ON_VIDEO_RES_CHANGED = "device.onVideoResolutionChanged"; - static constexpr const char* EVENT_ON_SCREEN_RES_CHANGED = "device.onScreenResolutionChanged"; - static constexpr const char* EVENT_ON_HDR_CHANGED = "device.onHdrChanged"; - static constexpr const char* EVENT_ON_HDCP_CHANGED = "device.onHdcpChanged"; - static constexpr const char* EVENT_ON_AUDIO_CHANGED = "device.onAudioChanged"; - static constexpr const char* EVENT_ON_NAME_CHANGED = "device.onDeviceNameChanged"; - - SystemDelegate(PluginHost::IShell *shell) - : BaseEventDelegate() - , _shell(shell) - , _subscriptions() - , _displayRpc(nullptr) - , _hdcpRpc(nullptr) - , _systemRpc(nullptr) - , _displaySubscribed(false) - , _displayAudioSubscribed(false) - , _hdcpSubscribed(false) - , _systemSubscribed(false) - { - // Proactively subscribe to underlying Thunder events so we can react quickly. - // Actual dispatch to apps only happens if registrations exist (BaseEventDelegate check). - SetupDisplaySettingsSubscription(); - SetupDisplaySettingsAudioSubscription(); - SetupHdcpProfileSubscription(); - SetupSystemSubscription(); - } - - ~SystemDelegate() - { - // Cleanup subscriptions - try { - if (_displayRpc) { - if (_displaySubscribed) { - _displayRpc->Unsubscribe(2000, _T("resolutionChanged")); - } - if (_displayAudioSubscribed) { - _displayRpc->Unsubscribe(2000, _T("audioFormatChanged")); - } - } - if (_hdcpRpc && _hdcpSubscribed) { - _hdcpRpc->Unsubscribe(2000, _T("onDisplayConnectionChanged")); - } - if (_systemRpc && _systemSubscribed) { - _systemRpc->Unsubscribe(2000, _T("onFriendlyNameChanged")); - } - } catch (...) { - // Safe-guard against destructor exceptions - } - _displayRpc.reset(); - _hdcpRpc.reset(); - _systemRpc.reset(); - _shell = nullptr; - } - - // PUBLIC_INTERFACE - Core::hresult GetDeviceMake(std::string &make) - { - /** Retrieve the device make using org.rdk.System.getDeviceInfo */ - LOGINFO("GetDeviceMake FbSettings Delegate"); - make.clear(); - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - make = "unknown"; - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getDeviceInfo", params, response); - if (rc == Core::ERROR_NONE) - { - if (response.HasLabel(_T("make"))) - { - make = response[_T("make")].String(); - } - } - - if (make.empty()) - { - // Per transform: return_or_else(.result.make, "unknown") - make = "unknown"; - } - // Wrap in quotes to make it a valid JSON string - make = "\"" + make + "\""; - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetDeviceName(std::string &name) - { - /** Retrieve the friendly name using org.rdk.System.getFriendlyName */ - name.clear(); - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - name = "Living Room"; - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getFriendlyName", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("friendlyName"))) - { - name = response[_T("friendlyName")].String(); - } - - // Default if empty - if (name.empty()) - { - name = "Living Room"; - } - // Wrap in quotes to make it a valid JSON string - name = "\"" + name + "\""; - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult SetDeviceName(const std::string &name) - { - /** Set the friendly name using org.rdk.System.setFriendlyName */ - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - params[_T("friendlyName")] = name; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("setFriendlyName", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("success")) && response[_T("success")].Boolean()) - { - return Core::ERROR_NONE; - } - LOGERR("SystemDelegate: couldn't set name"); - return Core::ERROR_GENERAL; - } - - // PUBLIC_INTERFACE - Core::hresult GetDeviceSku(std::string &skuOut) - { - /** Retrieve the device SKU from org.rdk.System.getSystemVersions.stbVersion */ - skuOut.clear(); - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getSystemVersions", params, response); - if (rc != Core::ERROR_NONE) - { - LOGERR("SystemDelegate: getSystemVersions failed rc=%u", rc); - return Core::ERROR_UNAVAILABLE; - } - if (!response.HasLabel(_T("stbVersion"))) - { - LOGERR("SystemDelegate: getSystemVersions missing stbVersion"); - return Core::ERROR_UNAVAILABLE; - } - - const std::string stbVersion = response[_T("stbVersion")].String(); - // Per transform: split("_")[0] - auto pos = stbVersion.find('_'); - skuOut = (pos == std::string::npos) ? stbVersion : stbVersion.substr(0, pos); - if (skuOut.empty()) - { - LOGERR("SystemDelegate: Failed to get SKU"); - return Core::ERROR_UNAVAILABLE; - } - // Wrap in quotes to make it a valid JSON string - skuOut = "\"" + skuOut + "\""; - return Core::ERROR_NONE; - } - - Core::hresult GetFirmwareVersion(std::string &version) - { - mAdminLock.Lock(); - version = mVersionResponse; - mAdminLock.Unlock(); - - if (!version.empty()) { - return Core::ERROR_NONE; - } - - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getSystemVersions", params, response); - if (rc != Core::ERROR_NONE) - { - LOGERR("SystemDelegate: getSystemVersions failed rc=%u", rc); - return Core::ERROR_UNAVAILABLE; - } - if (!response.HasLabel(_T("receiverVersion"))) { - LOGERR("SystemDelegate: getSystemVersions missing receiverVersion"); - return Core::ERROR_UNAVAILABLE; - } - std::string receiverVersion = response[_T("receiverVersion")].String(); - if (receiverVersion.empty()) - { - LOGERR("SystemDelegate: Failed to get Version"); - return Core::ERROR_UNAVAILABLE; - } - - std::string stbVersion = response[_T("stbVersion")].String(); - if (stbVersion.empty()) - { - LOGERR("SystemDelegate: Failed to get STB Version"); - return Core::ERROR_UNAVAILABLE; - } - - // receiver version is typically in 99.99.15.07 format need to set extract the first three parts only for major.minor.patch - // if receiverversion is not in number format return error - uint32_t major; - uint32_t minor; - uint32_t patch; - - if (sscanf(receiverVersion.c_str(), "%u.%u.%u", &major, &minor, &patch) != 3) - { - LOGERR("SystemDelegate: receiverVersion is not in number format"); - return Core::ERROR_UNAVAILABLE; - } - - JsonObject versionObj; - JsonObject api; - api["major"] = 1; - api["minor"] = 7; - api["patch"] = 0; - api["readable"] = "Firebolt API v1.7.0"; - - JsonObject firmwareInfo; - firmwareInfo["major"] = major; - firmwareInfo["minor"] = minor; - firmwareInfo["patch"] = patch; - firmwareInfo["readable"] = stbVersion; - // Build this json data structure {"api":{"major":1,"minor":7,"patch":0,"readable":"Firebolt API v1.7.0"},"firmware":{"major":99,"minor":99,"patch":15,"readable":"SKXI11ADS_MIDDLEWARE_DEV_develop_20251101123542_TEST_CD"},"os":{"major":99,"minor":99,"patch":15,"readable":"SKXI11ADS_MIDDLEWARE_DEV_develop_20251101123542_TEST_CD"},"debug":"4.0.0"} - versionObj["api"] = api; - versionObj["firmware"] = firmwareInfo; - versionObj["os"] = firmwareInfo; - versionObj["debug"] = "4.0.0"; - - mAdminLock.Lock(); - versionObj.ToString(mVersionResponse); - version = mVersionResponse; - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetCountryCode(std::string &code) - { - /** Retrieve Firebolt country code derived from org.rdk.System.getTerritory */ - code.clear(); - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - code = "US"; - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getTerritory", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("territory"))) - { - const std::string terr = response[_T("territory")].String(); - code = TerritoryThunderToFirebolt(terr, ""); - } - - // Wrap in quotes to make it a valid JSON string - code = "\"" + code + "\""; - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult SetCountryCode(const std::string &code) - { - /** Set territory using org.rdk.System.setTerritory mapped from Firebolt country code */ - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - const std::string territory = TerritoryFireboltToThunder(code, "USA"); - WPEFramework::Core::JSON::VariantContainer params; - params[_T("territory")] = territory; - - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("setTerritory", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("success")) && response[_T("success")].Boolean()) - { - return Core::ERROR_NONE; - } - LOGERR("SystemDelegate: couldn't set countrycode"); - return Core::ERROR_GENERAL; - } - - // PUBLIC_INTERFACE - Core::hresult GetTimeZone(std::string &tz) - { - /** Retrieve timezone using org.rdk.System.getTimeZoneDST */ - tz.clear(); - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getTimeZoneDST", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("success")) && response[_T("success")].Boolean()) - { - if (response.HasLabel(_T("timeZone"))) - { - tz = response[_T("timeZone")].String(); - // Wrap in quotes to make it a valid JSON string - tz = "\"" + tz + "\""; - return Core::ERROR_NONE; - } - } - LOGERR("SystemDelegate: couldn't get timezone"); - return Core::ERROR_UNAVAILABLE; - } - - // PUBLIC_INTERFACE - Core::hresult SetTimeZone(const std::string &tz) - { - /** Set timezone using org.rdk.System.setTimeZoneDST */ - auto link = AcquireLink(SYSTEM_CALLSIGN); - if (!link) - { - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - params[_T("timeZone")] = tz; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("setTimeZoneDST", params, response); - if (rc == Core::ERROR_NONE && response.HasLabel(_T("success")) && response[_T("success")].Boolean()) - { - return Core::ERROR_NONE; - } - LOGERR("SystemDelegate: couldn't set timezone"); - return Core::ERROR_GENERAL; - } - - // PUBLIC_INTERFACE - Core::hresult GetSecondScreenFriendlyName(std::string &name) - { - /** Alias to GetDeviceName using org.rdk.System.getFriendlyName */ - return GetDeviceName(name); - } - - // PUBLIC_INTERFACE - Core::hresult GetScreenResolution(std::string &jsonArray) - { - /** - * Get [w, h] screen resolution using DisplaySettings.getCurrentResolution. - * Returns "[1920,1080]" as fallback when unavailable. - */ - LOGDBG("[FbSettings|GetScreenResolution] Invoked"); - jsonArray = "[1920,1080]"; - auto link = AcquireLink(DISPLAYSETTINGS_CALLSIGN); - if (!link) { - LOGERR("[FbSettings|GetScreenResolution] DisplaySettings link unavailable, returning default %s", jsonArray.c_str()); - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getCurrentResolution", params, response); - if (rc != Core::ERROR_NONE) { - LOGERR("[FbSettings|GetScreenResolution] getCurrentResolution failed rc=%u, returning default %s", rc, jsonArray.c_str()); - return Core::ERROR_GENERAL; - } - - int w = 1920, h = 1080; - - // Try top-level first - if (response.HasLabel(_T("w")) && response.HasLabel(_T("h"))) { - auto wv = response.Get(_T("w")); - auto hv = response.Get(_T("h")); - if (wv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER && - hv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER) { - w = static_cast(wv.Number()); - h = static_cast(hv.Number()); - } - } else if (response.HasLabel(_T("result"))) { - // Try nested "result" - auto r = response.Get(_T("result")); - if (r.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - auto wnv = r.Object().Get(_T("w")); - auto hnv = r.Object().Get(_T("h")); - auto wdv = r.Object().Get(_T("width")); - auto hdv = r.Object().Get(_T("height")); - - if (wnv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER && - hnv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER) { - w = static_cast(wnv.Number()); - h = static_cast(hnv.Number()); - } else if (wdv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER && - hdv.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER) { - w = static_cast(wdv.Number()); - h = static_cast(hdv.Number()); - } - } - } - - jsonArray = "[" + std::to_string(w) + "," + std::to_string(h) + "]"; - LOGDBG("[FbSettings|GetScreenResolution] Computed screenResolution: w=%d h=%d -> %s", w, h, jsonArray.c_str()); - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetVideoResolution(std::string &jsonArray) - { - /** - * Get [w, h] video resolution. Prefer DisplaySettings.getCurrentResolution width - * to infer UHD vs FHD; else default to 1080p. - * This is a stubbed approximation of the /system/hdmi.uhdConfigured logic. - */ - std::string sr; - (void)GetScreenResolution(sr); - // sr expected format: "[w,h]" - int w = 1920, h = 1080; - if (sr.size() > 2 && sr.front() == '[' && sr.back() == ']') { - try { - // Simple parsing without heavy JSON dependencies - auto comma = sr.find(','); - if (comma != std::string::npos) { - int sw = std::stoi(sr.substr(1, comma - 1)); - int sh = std::stoi(sr.substr(comma + 1, sr.size() - comma - 2)); - if (sw >= 3840 || sh >= 2160) { - w = 3840; h = 2160; - } else { - w = 1920; h = 1080; - } - LOGDBG("[FbSettings|GetVideoResolution] Transform screen(%d x %d) -> video(%d x %d)", sw, sh, w, h); - } - } catch (...) { - // keep defaults - LOGDBG("[FbSettings|GetVideoResolution] Transform parse error for %s -> using defaults (%d x %d)", sr.c_str(), w, h); - } - } - jsonArray = "[" + std::to_string(w) + "," + std::to_string(h) + "]"; - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetHdcp(std::string &jsonObject) - { - /** - * Get HDCP status via HdcpProfile.getHDCPStatus. - * Return {"hdcp1.4":bool,"hdcp2.2":bool} with sensible defaults. - */ - jsonObject = "{\"hdcp1.4\":false,\"hdcp2.2\":false}"; - LOGDBG("[FbSettings|GetHdcp] Invoked"); - auto link = AcquireLink(HDCPPROFILE_CALLSIGN); - if (!link) { - LOGERR("[FbSettings|GetHdcp] HdcpProfile link unavailable, returning default %s", jsonObject.c_str()); - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getHDCPStatus", params, response); - if (rc != Core::ERROR_NONE) { - LOGERR("[FbSettings|GetHdcp] getHDCPStatus failed rc=%u, returning default %s", rc, jsonObject.c_str()); - return Core::ERROR_GENERAL; - } - - bool hdcp14 = false; - bool hdcp22 = false; - - // Prefer nested "result" if available - if (response.HasLabel(_T("result"))) { - auto r = response.Get(_T("result")); - if (r.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - auto succ = r.Object().Get(_T("success")); - auto status = r.Object().Get(_T("HDCPStatus")); - if (succ.Content() == WPEFramework::Core::JSON::Variant::type::BOOLEAN && succ.Boolean() && - status.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - auto reason = status.Object().Get(_T("hdcpReason")); - auto version = status.Object().Get(_T("currentHDCPVersion")); - if (reason.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER && - static_cast(reason.Number()) == 2 && - version.Content() == WPEFramework::Core::JSON::Variant::type::STRING) { - const std::string v = version.String(); - if (v == "1.4") { hdcp14 = true; } - else { hdcp22 = true; } - } - } - } - } else { - // Fallback: try top-level fields if present - auto status = response.Get(_T("HDCPStatus")); - if (status.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - auto reason = status.Object().Get(_T("hdcpReason")); - auto version = status.Object().Get(_T("currentHDCPVersion")); - if (reason.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER && - static_cast(reason.Number()) == 2 && - version.Content() == WPEFramework::Core::JSON::Variant::type::STRING) { - const std::string v = version.String(); - if (v == "1.4") { hdcp14 = true; } - else { hdcp22 = true; } - } - } - } - - jsonObject = std::string("{\"hdcp1.4\":") + (hdcp14 ? "true" : "false") - + ",\"hdcp2.2\":" + (hdcp22 ? "true" : "false") + "}"; - LOGDBG("[FbSettings|GetHdcp] Computed HDCP flags: hdcp1.4=%s hdcp2.2=%s -> %s", - hdcp14 ? "true" : "false", hdcp22 ? "true" : "false", jsonObject.c_str()); - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetHdr(std::string &jsonObject) - { - /** - * Retrieve HDR capability/state via DisplaySettings.getTVHDRCapabilities. - * Returns object with hdr10, dolbyVision, hlg, hdr10Plus flags (defaults false). - */ - jsonObject = "{\"hdr10\":false,\"dolbyVision\":false,\"hlg\":false,\"hdr10Plus\":false}"; - LOGDBG("[FbSettings|GetHdr] Invoked"); - auto link = AcquireLink(DISPLAYSETTINGS_CALLSIGN); - if (!link) { - LOGERR("[FbSettings|GetHdr] DisplaySettings link unavailable, returning default %s", jsonObject.c_str()); - return Core::ERROR_UNAVAILABLE; - } - - WPEFramework::Core::JSON::VariantContainer params; - WPEFramework::Core::JSON::VariantContainer response; - const uint32_t rc = link->Invoke("getTVHDRCapabilities", params, response); - if (rc != Core::ERROR_NONE) { - LOGERR("[FbSettings|GetHdr] getTVHDRCapabilities failed rc=%u, returning default %s", rc, jsonObject.c_str()); - return Core::ERROR_GENERAL; - } - - bool hdr10 = false, dv = false, hlg = false, hdr10plus = false; - - // Parse HDR capabilities bitmask - // HDRSTANDARD_NONE = 0x0 - // HDRSTANDARD_HDR10 = 0x1 - // HDRSTANDARD_HLG = 0x2 - // HDRSTANDARD_DolbyVision = 0x4 - // HDRSTANDARD_TechnicolorPrime = 0x8 - // HDRSTANDARD_HDR10PLUS = 0x10 - // HDRSTANDARD_SDR = 0x20 - - auto parseCapabilities = [&](const WPEFramework::Core::JSON::Variant& vobj) { - uint32_t capabilities = 0; - - // For ex. if DisplaySettings returns: {"capabilities":32,"success":true} - // extract the "capabilities" field from the object - if (vobj.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - auto caps = vobj.Object().Get(_T("capabilities")); - if (caps.Content() == WPEFramework::Core::JSON::Variant::type::NUMBER) { - capabilities = static_cast(caps.Number()); - LOGDBG("[FbSettings|GetHdr] Got capabilities from object: 0x%x (%d)", - capabilities, capabilities); - } - } - - // Parse bitmask - always parse, even if 0 (HDRSTANDARD_NONE is valid) - hdr10 = (capabilities & 0x01) != 0; // HDRSTANDARD_HDR10 - hlg = (capabilities & 0x02) != 0; // HDRSTANDARD_HLG - dv = (capabilities & 0x04) != 0; // HDRSTANDARD_DolbyVision - hdr10plus = (capabilities & 0x10) != 0; // HDRSTANDARD_HDR10PLUS - LOGDBG("[FbSettings|GetHdr] Parsed capabilities bitmask: 0x%x -> hdr10=%d hlg=%d dv=%d hdr10plus=%d", - capabilities, hdr10, hlg, dv, hdr10plus); - }; - - // Response is at top level: {"capabilities":32,"success":true} - parseCapabilities(response); - - jsonObject = std::string("{\"hdr10\":") + (hdr10 ? "true" : "false") - + ",\"dolbyVision\":" + (dv ? "true" : "false") - + ",\"hlg\":" + (hlg ? "true" : "false") - + ",\"hdr10Plus\":" + (hdr10plus ? "true" : "false") + "}"; - LOGDBG("[FbSettings|GetHdr] Computed HDR flags: hdr10=%s dolbyVision=%s hlg=%s hdr10Plus=%s -> %s", - hdr10 ? "true" : "false", - dv ? "true" : "false", - hlg ? "true" : "false", - hdr10plus ? "true" : "false", - jsonObject.c_str()); - return Core::ERROR_NONE; - } - - // PUBLIC_INTERFACE - Core::hresult GetAudio(std::string &jsonObject) - { - /** - * Retrieve supported audio formats from DisplaySettings.getAudioFormat(audioPort: "HDMI0") and - * compute flags from supportedAudioFormat array only. Multiple true values are allowed. - * Flags: - * - stereo: true if a token contains "PCM" or "STEREO" - * - dolbyDigital5.1: true if a token contains "AC3" or "DOLBY AC3" - * - dolbyDigital5.1+: true if a token contains any of "EAC3", "DD+", or "AC4" - * - dolbyAtmos: true if a token contains "ATMOS" - */ - bool stereo = false; - bool dd51 = false; - bool dd51p = false; - bool atmos = false; - - auto link = AcquireLink(DISPLAYSETTINGS_CALLSIGN); - if (!link) { - LOGERR("[FbSettings|GetAudio] DisplaySettings link unavailable, returning default audio flags"); - jsonObject = "{\"stereo\":false,\"dolbyDigital5.1\":false,\"dolbyDigital5.1+\":false,\"dolbyAtmos\":false}"; - return Core::ERROR_UNAVAILABLE; - } - - const std::string paramsStr = "{\"audioPort\":\"HDMI0\"}"; - std::string response; - const Core::hresult rc = link->Invoke("getAudioFormat", paramsStr, response); - if (rc != Core::ERROR_NONE) { - jsonObject = "{\"stereo\":false,\"dolbyDigital5.1\":false,\"dolbyDigital5.1+\":false,\"dolbyAtmos\":false}"; - return Core::ERROR_GENERAL; - } - - WPEFramework::Core::JSON::VariantContainer v; - WPEFramework::Core::OptionalType error; - if (v.FromString(response, error)) { - WPEFramework::Core::JSON::Variant supported; - if (v.HasLabel(_T("result"))) { - auto r = v.Get(_T("result")); - if (r.Content() == WPEFramework::Core::JSON::Variant::type::OBJECT) { - supported = r.Object().Get(_T("supportedAudioFormat")); - } - } - if (supported.Content() != WPEFramework::Core::JSON::Variant::type::ARRAY) { - supported = v.Get(_T("supportedAudioFormat")); - } - // Aggregate flags only from supportedAudioFormat - (void)SetFlagsFromSupported(supported, stereo, dd51, dd51p, atmos); - } - - jsonObject = std::string("{\"stereo\":") + (stereo ? "true" : "false") - + ",\"dolbyDigital5.1\":" + (dd51 ? "true" : "false") - + ",\"dolbyDigital5.1+\":" + (dd51p ? "true" : "false") - + ",\"dolbyAtmos\":" + (atmos ? "true" : "false") + "}"; - return Core::ERROR_NONE; - } - - /** - * Helper: Parse supportedAudioFormat array and set flags. Returns true iff an array was found - * and at least one recognized token was matched. Tokens are matched case-insensitively: - * - stereo: contains "PCM" or "STEREO" - * - dolbyDigital5.1: contains "AC3" or "DOLBY AC3" or "DOLBY DIGITAL" - * - dolbyDigital5.1+: contains "EAC3" or "DD+" or "DOLBY DIGITAL PLUS" or "AC4" - * - dolbyAtmos: contains "ATMOS" - */ - static bool SetFlagsFromSupported(const WPEFramework::Core::JSON::Variant& supportedNode, - bool& stereo, bool& dd51, bool& dd51p, bool& atmos) - { - using Var = WPEFramework::Core::JSON::Variant; - bool anyRecognized = false; - if (supportedNode.Content() == Var::type::ARRAY) { - auto arr = supportedNode.Array(); - const uint16_t n = arr.Length(); - for (uint16_t i = 0; i < n; ++i) { - std::string token = arr[i].String(); - if (token.empty()) { - continue; - } - std::string u = token; - std::transform(u.begin(), u.end(), u.begin(), [](unsigned char c){ return static_cast(::toupper(c)); }); - - // Stereo detection - if (u.find("PCM") != std::string::npos || u.find("STEREO") != std::string::npos) { - stereo = true; anyRecognized = true; - } - // Dolby Digital (AC3) - // Only match "AC3" if not preceded by 'E' (i.e., not "EAC3") - bool isAC3 = false; - // Check for "AC3" not preceded by 'E' - size_t ac3_pos = u.find("AC3"); - if (ac3_pos != std::string::npos) { - if (ac3_pos == 0 || u[ac3_pos - 1] != 'E') { - isAC3 = true; - } - } - if (isAC3 || u.find("DOLBY AC3") != std::string::npos || u.find("DOLBY DIGITAL") != std::string::npos) { - dd51 = true; anyRecognized = true; - } - // Dolby Digital Plus (EAC3/DD+/AC4) - if (u.find("EAC3") != std::string::npos || u.find("DD+") != std::string::npos || u.find("DOLBY DIGITAL PLUS") != std::string::npos || u.find("AC4") != std::string::npos) { - dd51p = true; anyRecognized = true; - } - // Atmos (any transport) - if (u.find("ATMOS") != std::string::npos) { - atmos = true; anyRecognized = true; - } - } - } - return anyRecognized; - } - - // ---- Event exposure (Emit helpers) ---- - - // PUBLIC_INTERFACE - bool EmitOnVideoResolutionChanged() - { - std::string payload; - if (GetVideoResolution(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|VideoResolutionChanged] handler=GetVideoResolution failed to compute payload"); - return false; - } - // Transform to rpcv2_event wrapper: { "videoResolution": $event_handler_response } - const std::string wrapped = std::string("{\"videoResolution\":") + payload + "}"; - LOGINFO("[FbSettings|VideoResolutionChanged] Final rpcv2_event payload=%s", wrapped.c_str()); - LOGDBG("[FbSettings|VideoResolutionChanged] Emitting event: %s", EVENT_ON_VIDEO_RES_CHANGED); - Dispatch(EVENT_ON_VIDEO_RES_CHANGED, wrapped); - return true; - } - - // PUBLIC_INTERFACE - bool EmitOnScreenResolutionChanged() - { - std::string payload; - if (GetScreenResolution(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|ScreenResolutionChanged] handler=GetScreenResolution failed to compute payload"); - return false; - } - // Transform to rpcv2_event wrapper: { "screenResolution": $event } - const std::string wrapped = std::string("{\"screenResolution\":") + payload + "}"; - LOGINFO("[FbSettings|ScreenResolutionChanged] Final rpcv2_event payload=%s", wrapped.c_str()); - LOGDBG("[FbSettings|ScreenResolutionChanged] Emitting event: %s", EVENT_ON_SCREEN_RES_CHANGED); - Dispatch(EVENT_ON_SCREEN_RES_CHANGED, wrapped); - return true; - - } - - // PUBLIC_INTERFACE - bool EmitOnHdcpChanged() - { - std::string payload; - if (GetHdcp(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|HdcpChanged] handler=GetHdcp failed to compute payload"); - return false; - } - LOGINFO("[FbSettings|HdcpChanged] Final rpcv2_event payload=%s", payload.c_str()); - LOGDBG("[FbSettings|HdcpChanged] Emitting event: %s", EVENT_ON_HDCP_CHANGED); - Dispatch(EVENT_ON_HDCP_CHANGED, payload); - return true; - - } - - // PUBLIC_INTERFACE - bool EmitOnHdrChanged() - { - std::string payload; - if (GetHdr(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|HdrChanged] handler=GetHdr failed to compute payload"); - return false; - } - LOGINFO("[FbSettings|HdrChanged] Final rpcv2_event payload=%s", payload.c_str()); - LOGDBG("[FbSettings|HdrChanged] Emitting event: %s", EVENT_ON_HDR_CHANGED); - Dispatch(EVENT_ON_HDR_CHANGED, payload); - return true; - - } - - // PUBLIC_INTERFACE - bool EmitOnNameChanged() - { - std::string payload; - if (GetDeviceName(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|NameChanged] handler=GetDeviceName failed to compute payload"); - return false; - } - // Transform to rpcv2_event wrapper: { "friendlyName": $event } - const std::string wrapped = std::string("{\"friendlyName\":") + payload + "}"; - LOGINFO("[FbSettings|NameChanged] Final rpcv2_event payload=%s", wrapped.c_str()); - LOGDBG("[FbSettings|NameChanged] Emitting event: %s", EVENT_ON_NAME_CHANGED); - Dispatch(EVENT_ON_NAME_CHANGED, wrapped); - return true; - } - - // PUBLIC_INTERFACE - bool EmitOnAudioChanged() - { - std::string payload; - if (GetAudio(payload) != Core::ERROR_NONE) { - LOGERR("[FbSettings|AudioChanged] handler=GetAudio failed to compute payload"); - return false; - } - LOGINFO("[FbSettings|AudioChanged] Final rpcv2_event payload=%s", payload.c_str()); - LOGDBG("[FbSettings|AudioChanged] Emitting event: %s", EVENT_ON_AUDIO_CHANGED); - Dispatch(EVENT_ON_AUDIO_CHANGED, payload); - return true; - } - - // ---- AppNotifications registration hook ---- - // Called by SettingsDelegate when app subscribes/unsubscribes to events. - bool HandleEvent(Exchange::IAppNotificationHandler::IEmitter *cb, const std::string &event, const bool listen, bool ®istrationError) - { - registrationError = false; - - const std::string evLower = ToLower(event); - - // Supported events (case-insensitive) - if (evLower == "device.onvideoresolutionchanged" - || evLower == "device.onscreenresolutionchanged" - || evLower == "device.onhdcpchanged" - || evLower == "device.onhdrchanged" - || evLower == "device.onaudiochanged" - || evLower == "device.ondevicenamechanged" - || evLower == "device.onnamechanged") - { - LOGINFO("[FbSettings|EventRegistration] event=%s listen=%s", event.c_str(), listen ? "true" : "false"); - if (listen) { - AddNotification(event, cb); - // Ensure underlying Thunder subscriptions are active - SetupDisplaySettingsSubscription(); - SetupDisplaySettingsAudioSubscription(); - SetupHdcpProfileSubscription(); - SetupSystemSubscription(); - registrationError = false; // no error - successfully handled - return true; - } else { - RemoveNotification(event, cb); - registrationError = false; // no error - successfully handled - return true; - } - } - return false; - } - - -private: - inline std::shared_ptr AcquireLink(const std::string& callsign) const - { - // Create a direct JSON-RPC link to the specified Thunder plugin using the Supporting_Files helper. - if (_shell == nullptr) - { - LOGERR("SystemDelegate: shell is null"); - return nullptr; - } - return WPEFramework::Utils::GetThunderControllerClient(_shell, callsign); - } - - static std::string ToLower(const std::string &in) - { - std::string out; - out.reserve(in.size()); - for (char c : in) - { - out.push_back(static_cast(::tolower(static_cast(c)))); - } - return out; - } - - static std::string TerritoryThunderToFirebolt(const std::string &terr, const std::string &deflt) - { - if (EqualsIgnoreCase(terr, "USA")) - return "US"; - if (EqualsIgnoreCase(terr, "CAN")) - return "CA"; - if (EqualsIgnoreCase(terr, "ITA")) - return "IT"; - if (EqualsIgnoreCase(terr, "GBR")) - return "GB"; - if (EqualsIgnoreCase(terr, "IRL")) - return "IE"; - if (EqualsIgnoreCase(terr, "AUS")) - return "AU"; - if (EqualsIgnoreCase(terr, "AUT")) - return "AT"; - if (EqualsIgnoreCase(terr, "CHE")) - return "CH"; - if (EqualsIgnoreCase(terr, "DEU")) - return "DE"; - return deflt; - } - - static std::string TerritoryFireboltToThunder(const std::string &code, const std::string &deflt) - { - if (EqualsIgnoreCase(code, "US")) - return "USA"; - if (EqualsIgnoreCase(code, "CA")) - return "CAN"; - if (EqualsIgnoreCase(code, "IT")) - return "ITA"; - if (EqualsIgnoreCase(code, "GB")) - return "GBR"; - if (EqualsIgnoreCase(code, "IE")) - return "IRL"; - if (EqualsIgnoreCase(code, "AU")) - return "AUS"; - if (EqualsIgnoreCase(code, "AT")) - return "AUT"; - if (EqualsIgnoreCase(code, "CH")) - return "CHE"; - if (EqualsIgnoreCase(code, "DE")) - return "DEU"; - return deflt; - } - - static bool EqualsIgnoreCase(const std::string &a, const std::string &b) - { - if (a.size() != b.size()) - return false; - for (size_t i = 0; i < a.size(); ++i) - { - if (::tolower(static_cast(a[i])) != ::tolower(static_cast(b[i]))) - { - return false; - } - } - return true; - } - // Setup subscriptions to underlying Thunder plugin events - void SetupDisplaySettingsSubscription() - { - if (_displaySubscribed) return; - try { - if (!_displayRpc) { - _displayRpc = ::Utils::getThunderControllerClient(DISPLAYSETTINGS_CALLSIGN); - } - if (_displayRpc) { - const uint32_t status = _displayRpc->Subscribe( - 2000, _T("resolutionChanged"), &SystemDelegate::OnDisplaySettingsResolutionChanged, this); - if (status == Core::ERROR_NONE) { - LOGINFO("SystemDelegate: Subscribed to %s.resolutionChanged", DISPLAYSETTINGS_CALLSIGN); - _displaySubscribed = true; - } else { - LOGERR("SystemDelegate: Failed to subscribe to %s.resolutionChanged rc=%u", DISPLAYSETTINGS_CALLSIGN, status); - } - } - } catch (...) { - LOGERR("SystemDelegate: exception during DisplaySettings (resolution) subscription"); - } - } - - void SetupDisplaySettingsAudioSubscription() - { - if (_displayAudioSubscribed) return; - try { - if (!_displayRpc) { - _displayRpc = ::Utils::getThunderControllerClient(DISPLAYSETTINGS_CALLSIGN); - } - if (_displayRpc) { - const uint32_t status = _displayRpc->Subscribe( - 2000, _T("audioFormatChanged"), &SystemDelegate::OnDisplaySettingsAudioFormatChanged, this); - if (status == Core::ERROR_NONE) { - LOGINFO("SystemDelegate: Subscribed to %s.audioFormatChanged", DISPLAYSETTINGS_CALLSIGN); - _displayAudioSubscribed = true; - } else { - LOGERR("SystemDelegate: Failed to subscribe to %s.audioFormatChanged rc=%u", DISPLAYSETTINGS_CALLSIGN, status); - } - } - } catch (...) { - LOGERR("SystemDelegate: exception during DisplaySettings (audio) subscription"); - } - } - - void SetupHdcpProfileSubscription() - { - if (_hdcpSubscribed) return; - try { - if (!_hdcpRpc) { - _hdcpRpc = ::Utils::getThunderControllerClient(HDCPPROFILE_CALLSIGN); - } - if (_hdcpRpc) { - const uint32_t status = _hdcpRpc->Subscribe( - 2000, _T("onDisplayConnectionChanged"), &SystemDelegate::OnHdcpProfileDisplayConnectionChanged, this); - if (status == Core::ERROR_NONE) { - LOGINFO("SystemDelegate: Subscribed to %s.onDisplayConnectionChanged", HDCPPROFILE_CALLSIGN); - _hdcpSubscribed = true; - } else { - LOGERR("SystemDelegate: Failed to subscribe to %s.onDisplayConnectionChanged rc=%u", HDCPPROFILE_CALLSIGN, status); - } - } - } catch (...) { - LOGERR("SystemDelegate: exception during HdcpProfile subscription"); - } - } - - void SetupSystemSubscription() - { - if (_systemSubscribed) return; - try { - if (!_systemRpc) { - _systemRpc = ::Utils::getThunderControllerClient(SYSTEM_CALLSIGN); - } - if (_systemRpc) { - const uint32_t status = _systemRpc->Subscribe( - 2000, _T("onFriendlyNameChanged"), &SystemDelegate::OnSystemFriendlyNameChanged, this); - if (status == Core::ERROR_NONE) { - LOGINFO("SystemDelegate: Subscribed to %s.onFriendlyNameChanged", SYSTEM_CALLSIGN); - _systemSubscribed = true; - } else { - LOGERR("SystemDelegate: Failed to subscribe to %s.onFriendlyNameChanged rc=%u", SYSTEM_CALLSIGN, status); - } - } - } catch (...) { - LOGERR("SystemDelegate: exception during System subscription"); - } - } - - // Event handlers invoked by Thunder JSON-RPC subscription - void OnDisplaySettingsResolutionChanged(const WPEFramework::Core::JSON::VariantContainer& params) - { - (void)params; - LOGINFO("[FbSettings|DisplaySettings.resolutionChanged] Incoming alias=%s.%s, invoking handlers...", - DISPLAYSETTINGS_CALLSIGN, "resolutionChanged"); - // Re-query state and dispatch debounced events - const bool screenEmitted = EmitOnScreenResolutionChanged(); - const bool videoEmitted = EmitOnVideoResolutionChanged(); - LOGINFO("[FbSettings|DisplaySettings.resolutionChanged] Handler responses: onScreenResolutionChanged=%s onVideoResolutionChanged=%s", - screenEmitted ? "emitted" : "skipped", videoEmitted ? "emitted" : "skipped"); - } - - void OnHdcpProfileDisplayConnectionChanged(const WPEFramework::Core::JSON::VariantContainer& params) - { - (void)params; - LOGINFO("[FbSettings|HdcpProfile.onDisplayConnectionChanged] Incoming alias=%s.%s, invoking handlers...", - HDCPPROFILE_CALLSIGN, "onDisplayConnectionChanged"); - // Re-query state and dispatch debounced events - const bool hdcpEmitted = EmitOnHdcpChanged(); - const bool hdrEmitted = EmitOnHdrChanged(); - LOGINFO("[FbSettings|HdcpProfile.onDisplayConnectionChanged] Handler responses: onHdcpChanged=%s onHdrChanged=%s", - hdcpEmitted ? "emitted" : "skipped", hdrEmitted ? "emitted" : "skipped"); - } - - void OnSystemFriendlyNameChanged(const WPEFramework::Core::JSON::VariantContainer& params) - { - (void)params; - LOGINFO("[FbSettings|System.onFriendlyNameChanged] Incoming alias=%s.%s, invoking handlers...", - SYSTEM_CALLSIGN, "onFriendlyNameChanged"); - // Re-query state and dispatch event - const bool nameEmitted = EmitOnNameChanged(); - LOGINFO("[FbSettings|System.onFriendlyNameChanged] Handler responses: onNameChanged=%s", - nameEmitted ? "emitted" : "skipped"); - } - - void OnDisplaySettingsAudioFormatChanged(const WPEFramework::Core::JSON::VariantContainer& params) - { - (void)params; - LOGINFO("[FbSettings|DisplaySettings.audioFormatChanged] Incoming alias=%s.%s, invoking handlers...", - DISPLAYSETTINGS_CALLSIGN, "audioFormatChanged"); - // Re-query state and dispatch event - const bool audioEmitted = EmitOnAudioChanged(); - LOGINFO("[FbSettings|DisplaySettings.audioFormatChanged] Handler responses: onAudioChanged=%s", - audioEmitted ? "emitted" : "skipped"); - } - -private: - PluginHost::IShell *_shell; - std::unordered_set _subscriptions; - mutable Core::CriticalSection mAdminLock; - std::string mVersionResponse; - - // JSONRPC clients for event subscriptions - std::shared_ptr> _displayRpc; - std::shared_ptr> _hdcpRpc; - std::shared_ptr> _systemRpc; - bool _displaySubscribed; - bool _displayAudioSubscribed; - bool _hdcpSubscribed; - bool _systemSubscribed; -}; - diff --git a/FbSettings/delegate/UserSettingsDelegate.h b/FbSettings/delegate/UserSettingsDelegate.h deleted file mode 100644 index 1aa18cb..0000000 --- a/FbSettings/delegate/UserSettingsDelegate.h +++ /dev/null @@ -1,909 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#ifndef __USERSETTINGSDELEGATE_H__ -#define __USERSETTINGSDELEGATE_H__ -#include "StringUtils.h" -#include "BaseEventDelegate.h" -#include -#include "UtilsLogging.h" -#include "ObjectUtils.h" -#include -using namespace WPEFramework; -#define USERSETTINGS_CALLSIGN "org.rdk.UserSettings" - -static const std::set VALID_USER_SETTINGS_EVENT = { - "localization.onlanguagechanged", - "localization.onlocalechanged", - "localization.onpreferredaudiolanguageschanged", - "accessibility.onaudiodescriptionsettingschanged", - "accessibility.onhighcontrastuichanged", - "closedcaptions.onenabledchanged", - "closedcaptions.onpreferredlanguageschanged", - "accessibility.onclosedcaptionssettingschanged", - "accessibility.onvoiceguidancesettingschanged", -}; - -class UserSettingsDelegate : public BaseEventDelegate{ - public: - UserSettingsDelegate(PluginHost::IShell* shell): - BaseEventDelegate(), mUserSettings(nullptr), mShell(shell), mNotificationHandler(*this) {} - - ~UserSettingsDelegate() { - if (mUserSettings != nullptr) { - mUserSettings->Release(); - mUserSettings = nullptr; - } - } - - bool HandleSubscription(Exchange::IAppNotificationHandler::IEmitter *cb, const string &event, const bool listen) { - if (listen) { - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings interface not available"); - return false; - } - - AddNotification(event, cb); - - if (!mNotificationHandler.GetRegistered()) { - LOGINFO("Registering for UserSettings notifications"); - mUserSettings->Register(&mNotificationHandler); - mNotificationHandler.SetRegistered(true); - return true; - } else { - LOGTRACE(" Is UserSettings registered = %s", mNotificationHandler.GetRegistered() ? "true" : "false"); - } - - } else { - // Not removing the notification subscription for cases where only one event is removed - // Registration is lazy one but we need to evaluate if there is any value in unregistering - // given these API calls are always made - RemoveNotification(event, cb); - } - return false; - } - - bool HandleEvent(Exchange::IAppNotificationHandler::IEmitter *cb, const string &event, const bool listen, bool ®istrationError) { - LOGDBG("Checking for handle event"); - // Check if event is present in VALID_USER_SETTINGS_EVENT make check case insensitive - if (VALID_USER_SETTINGS_EVENT.find(StringUtils::toLower(event)) != VALID_USER_SETTINGS_EVENT.end()) { - // Handle TextToSpeech event - registrationError = HandleSubscription(cb, event, listen); - return true; - } - return false; - } - - // Common method to ensure mUserSettings is available for all APIs and notifications - Exchange::IUserSettings* GetUserSettingsInterface() { - if (mUserSettings == nullptr && mShell != nullptr) { - mUserSettings = mShell->QueryInterfaceByCallsign(USERSETTINGS_CALLSIGN); - if (mUserSettings == nullptr) { - LOGERR("Failed to get UserSettings COM interface"); - } - } - return mUserSettings; - } - - Core::hresult GetVoiceGuidance(string& result) { - LOGINFO("GetVoiceGuidance from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get voiceguidance state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool enabled = false; - Core::hresult rc = userSettings->GetVoiceGuidance(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform the response: return_or_error(.result, "couldnt get voiceguidance state") - // Return the boolean result directly as per transform specification - result = enabled ? "true" : "false"; - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetVoiceGuidance on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get voiceguidance state\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetAudioDescription(string& result) { - LOGINFO("GetAudioDescription from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get audio description settings\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool enabled = false; - Core::hresult rc = userSettings->GetAudioDescription(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform the response: return_or_error({ enabled: .result }, "couldnt get audio description settings") - // Create JSON response with enabled state - result = ObjectUtils::CreateBooleanJsonString("enabled", enabled); - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetAudioDescription on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get audio description settings\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetAudioDescriptionsEnabled(string& result) { - LOGINFO("GetAudioDescriptionsEnabled from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get audio descriptions enabled\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool enabled = false; - Core::hresult rc = userSettings->GetAudioDescription(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform the response: return_or_error(.result, "couldnt get audio descriptions enabled") - // Return the boolean result directly as per transform specification - result = enabled ? "true" : "false"; - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetAudioDescription on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get audio descriptions enabled\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetHighContrast(string& result) { - LOGINFO("GetHighContrast from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get high contrast state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool enabled = false; - Core::hresult rc = userSettings->GetHighContrast(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform the response: return_or_error(.result, "couldnt get audio descriptions enabled") - // Return the boolean result directly as per transform specification - result = enabled ? "true" : "false"; - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetHighContrast on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get high contrast state\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetCaptions(string& result) { - LOGINFO("GetCaptions from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get captions state\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool enabled = false; - Core::hresult rc = userSettings->GetCaptions(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform the response: return_or_error(.result, "couldnt get captions state") - // Return the boolean result directly as per transform specification - result = enabled ? "true" : "false"; - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetCaptions on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get captions state\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetVoiceGuidance(const bool enabled) { - LOGINFO("SetVoiceGuidance to UserSettings COM interface: %s", enabled ? "true" : "false"); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { enabled: .value } - // The enabled parameter is the .value from the request - Core::hresult rc = userSettings->SetVoiceGuidance(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set voiceguidance enabled") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetVoiceGuidance on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetAudioDescriptionsEnabled(const bool enabled) { - LOGINFO("SetAudioDescriptionsEnabled to UserSettings COM interface: %s", enabled ? "true" : "false"); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { enabled: .value } - // The enabled parameter is the .value from the request - Core::hresult rc = userSettings->SetAudioDescription(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set audio descriptions enabled") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetAudioDescription on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetCaptions(const bool enabled) { - LOGINFO("SetCaptions to UserSettings COM interface: %s", enabled ? "true" : "false"); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { enabled: .value } - // The enabled parameter is the .value from the request - Core::hresult rc = userSettings->SetCaptions(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set captions enabled") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetCaptions on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetVoiceGuidanceRate(const double rate) { - LOGINFO("SetVoiceGuidanceRate to UserSettings COM interface: %f", rate); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { rate: transformed_rate } - // The rate parameter is already the transformed value from vg_speed_firebolt2thunder - Core::hresult rc = userSettings->SetVoiceGuidanceRate(rate); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldnt set speed") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetVoiceGuidanceRate on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetVoiceGuidanceHints(const bool enabled) { - LOGINFO("SetVoiceGuidanceHints to UserSettings COM interface: %s", enabled ? "true" : "false"); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { enabled: .value } - // The enabled parameter is the .value from the request - Core::hresult rc = userSettings->SetVoiceGuidanceHints(enabled); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set voice guidance hints") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetVoiceGuidanceHints on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetVoiceGuidanceRate(double& rate) { - LOGINFO("GetVoiceGuidanceRate from UserSettings COM interface"); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - Core::hresult rc = userSettings->GetVoiceGuidanceRate(rate); - - if (rc == Core::ERROR_NONE) { - LOGINFO("Got voice guidance rate: %f", rate); - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetVoiceGuidanceRate on UserSettings COM interface, error: %u", rc); - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetVoiceGuidanceHints(string& result) { - LOGINFO("GetVoiceGuidanceHints from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldnt get navigationHints\"}"; - return Core::ERROR_UNAVAILABLE; - } - - bool hints = false; - Core::hresult rc = userSettings->GetVoiceGuidanceHints(hints); - - if (rc == Core::ERROR_NONE) { - // Transform: return_or_error(.result, "couldnt get navigationHints") - // Return the boolean result directly as per transform specification - result = hints ? "true" : "false"; - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetVoiceGuidanceHints on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldnt get navigationHints\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetPresentationLanguage(string& result) { - LOGINFO("GetPresentationLanguage from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldn't get language\"}"; - return Core::ERROR_UNAVAILABLE; - } - - string presentationLanguage; - Core::hresult rc = userSettings->GetPresentationLanguage(presentationLanguage); - - if (rc == Core::ERROR_NONE) { - // Transform: return_or_error(.result | split("-") | .[0], "couldn't get language") - if (!presentationLanguage.empty()) { - // Extract language part (before "-") from locale like "en-US" -> "en" - size_t dashPos = presentationLanguage.find('-'); - string language; - if (dashPos != string::npos) { - language = presentationLanguage.substr(0, dashPos); - } else { - // If no dash found, return the whole string - language = presentationLanguage; - } - // Wrap in quotes to make it a valid JSON string - result = "\"" + language + "\""; - return Core::ERROR_NONE; - } else { - result = "{\"error\":\"couldn't get language\"}"; - return Core::ERROR_GENERAL; - } - } else { - LOGERR("Failed to call GetPresentationLanguage on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldn't get language\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetLocale(string& result) { - LOGINFO("GetLocale from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "{\"error\":\"couldn't get locale\"}"; - return Core::ERROR_UNAVAILABLE; - } - - string presentationLanguage; - Core::hresult rc = userSettings->GetPresentationLanguage(presentationLanguage); - - if (rc == Core::ERROR_NONE) { - // Transform: return_or_error(.result, "couldn't get locale") - // Return the full locale without any transformation - if (!presentationLanguage.empty()) { - // Wrap in quotes to make it a valid JSON string - result = "\"" + presentationLanguage + "\""; - return Core::ERROR_NONE; - } else { - result = "{\"error\":\"couldn't get locale\"}"; - return Core::ERROR_GENERAL; - } - } else { - LOGERR("Failed to call GetPresentationLanguage on UserSettings COM interface, error: %u", rc); - result = "{\"error\":\"couldn't get locale\"}"; - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetLocale(const string& locale) { - LOGINFO("SetLocale to UserSettings COM interface: %s", locale.c_str()); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { presentationLanguage: .value } - // The locale parameter is the .value from the request - Core::hresult rc = userSettings->SetPresentationLanguage(locale); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set locale") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetPresentationLanguage on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetPreferredAudioLanguages(string& result) { - LOGINFO("GetPreferredAudioLanguages from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "[]"; // Return empty array on error - return Core::ERROR_UNAVAILABLE; - } - - string preferredLanguages; - Core::hresult rc = userSettings->GetPreferredAudioLanguages(preferredLanguages); - - if (rc == Core::ERROR_NONE) { - // Transform: return_or_else(.result | split(","), []) - if (!preferredLanguages.empty()) { - // Split comma-separated string into JSON array - // Example: "eng,fra,spa" -> ["eng","fra","spa"] - result = "["; - size_t pos = 0; - string token; - bool first = true; - - while ((pos = preferredLanguages.find(',')) != string::npos) { - token = preferredLanguages.substr(0, pos); - // Trim whitespace - token.erase(0, token.find_first_not_of(" \t")); - token.erase(token.find_last_not_of(" \t") + 1); - - if (!first) result += ","; - result += "\"" + token + "\""; - first = false; - preferredLanguages.erase(0, pos + 1); - } - - // Handle the last token - if (!preferredLanguages.empty()) { - preferredLanguages.erase(0, preferredLanguages.find_first_not_of(" \t")); - preferredLanguages.erase(preferredLanguages.find_last_not_of(" \t") + 1); - - if (!first) result += ","; - result += "\"" + preferredLanguages + "\""; - } - - result += "]"; - } else { - // Empty string case - return empty array - result = "[]"; - } - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetPreferredAudioLanguages on UserSettings COM interface, error: %u", rc); - result = "[]"; // Return empty array on error - return Core::ERROR_GENERAL; - } - } - - Core::hresult GetPreferredCaptionsLanguages(string& result) { - LOGINFO("GetPreferredCaptionsLanguages from UserSettings COM interface"); - result.clear(); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - result = "[\"eng\"]"; // Return default ["eng"] on error - return Core::ERROR_UNAVAILABLE; - } - - string preferredLanguages; - Core::hresult rc = userSettings->GetPreferredCaptionsLanguages(preferredLanguages); - - if (rc == Core::ERROR_NONE) { - // Transform: if .result | length > 0 then .result | split(",") else ["eng"] end - if (!preferredLanguages.empty()) { - // Split comma-separated string into JSON array - // Example: "eng,fra,spa" -> ["eng","fra","spa"] - result = "["; - size_t pos = 0; - string token; - bool first = true; - - while ((pos = preferredLanguages.find(',')) != string::npos) { - token = preferredLanguages.substr(0, pos); - // Trim whitespace - token.erase(0, token.find_first_not_of(" \t")); - token.erase(token.find_last_not_of(" \t") + 1); - - if (!first) result += ","; - result += "\"" + token + "\""; - first = false; - preferredLanguages.erase(0, pos + 1); - } - - // Handle the last token - if (!preferredLanguages.empty()) { - preferredLanguages.erase(0, preferredLanguages.find_first_not_of(" \t")); - preferredLanguages.erase(preferredLanguages.find_last_not_of(" \t") + 1); - - if (!first) result += ","; - result += "\"" + preferredLanguages + "\""; - } - - result += "]"; - } else { - // Empty string case - return ["eng"] as default - result = "[\"eng\"]"; - } - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call GetPreferredCaptionsLanguages on UserSettings COM interface, error: %u", rc); - result = "[\"eng\"]"; // Return default ["eng"] on error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetPreferredAudioLanguages(const string& languages) { - LOGINFO("SetPreferredAudioLanguages to UserSettings COM interface: %s", languages.c_str()); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { preferredLanguages: (.value | join(","))} - // The languages parameter can be either: - // 1. A JSON array: ["eng","fra","spa"] -> "eng,fra,spa" - // 2. A single string: "tam" -> "tam" - - string commaSeparatedLanguages; - - // Check if input is a JSON array - if (languages.length() >= 2 && languages[0] == '[' && languages.back() == ']') { - // Handle JSON array format - string arrayContent = languages.substr(1, languages.length() - 2); // Remove [ ] - - if (!arrayContent.empty()) { - // Use a cleaner parsing approach similar to GetPreferredAudioLanguages - string remaining = arrayContent; - bool first = true; - - while (!remaining.empty()) { - // Skip whitespace and commas - size_t start = remaining.find_first_not_of(" \t,"); - if (start == string::npos) break; - - remaining = remaining.substr(start); - - string token; - if (!remaining.empty() && remaining[0] == '"') { - // Find closing quote - size_t endQuote = remaining.find('"', 1); - if (endQuote != string::npos) { - token = remaining.substr(1, endQuote - 1); // Extract content between quotes - remaining = remaining.substr(endQuote + 1); - } else { - // Malformed JSON - no closing quote - LOGERR("Malformed JSON: missing closing quote"); - break; - } - } else { - // Malformed JSON - expected quoted string - LOGERR("Malformed JSON: expected quoted string"); - break; - } - - // Add token to result if not empty - if (!token.empty()) { - if (!first) commaSeparatedLanguages += ","; - commaSeparatedLanguages += token; - first = false; - } - } - } - } else if (languages == "[]") { - // Handle empty array case - commaSeparatedLanguages = ""; - } else { - // Handle single string value case (e.g., "tam") - // Remove quotes if present and use as-is - if (languages.length() >= 2 && languages[0] == '"' && languages.back() == '"') { - commaSeparatedLanguages = languages.substr(1, languages.length() - 2); - } else { - commaSeparatedLanguages = languages; - } - LOGINFO("Handling single string value: %s", commaSeparatedLanguages.c_str()); - } - - LOGINFO("Converted JSON array to comma-separated: %s", commaSeparatedLanguages.c_str()); - - Core::hresult rc = userSettings->SetPreferredAudioLanguages(commaSeparatedLanguages); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set preferred audio languages") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetPreferredAudioLanguages on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - Core::hresult SetPreferredCaptionsLanguages(const string& preferredLanguages) { - LOGINFO("SetPreferredCaptionsLanguages to UserSettings COM interface: %s", preferredLanguages.c_str()); - - Exchange::IUserSettings* userSettings = GetUserSettingsInterface(); - if (userSettings == nullptr) { - LOGERR("UserSettings COM interface not available"); - return Core::ERROR_UNAVAILABLE; - } - - // Transform request: { preferredLanguages: (.value | join(","))} - // The preferredLanguages parameter can be either: - // 1. A JSON array: ["eng","fra","spa"] -> "eng,fra,spa" - // 2. A single string: "tam" -> "tam" - - string commaSeparatedLanguages; - - // Check if input is a JSON array - if (preferredLanguages.length() >= 2 && preferredLanguages[0] == '[' && preferredLanguages.back() == ']') { - // Handle JSON array format - string arrayContent = preferredLanguages.substr(1, preferredLanguages.length() - 2); // Remove [ ] - - if (!arrayContent.empty()) { - // Use a cleaner parsing approach similar to SetPreferredAudioLanguages - string remaining = arrayContent; - bool first = true; - - while (!remaining.empty()) { - // Skip whitespace and commas - size_t start = remaining.find_first_not_of(" \t,"); - if (start == string::npos) break; - - remaining = remaining.substr(start); - - string token; - if (!remaining.empty() && remaining[0] == '"') { - // Find closing quote - size_t endQuote = remaining.find('"', 1); - if (endQuote != string::npos) { - token = remaining.substr(1, endQuote - 1); // Extract content between quotes - remaining = remaining.substr(endQuote + 1); - } else { - // Malformed JSON - no closing quote - LOGERR("Malformed JSON: missing closing quote"); - break; - } - } else { - // Malformed JSON - expected quoted string - LOGERR("Malformed JSON: expected quoted string"); - break; - } - - // Add token to result if not empty - if (!token.empty()) { - if (!first) commaSeparatedLanguages += ","; - commaSeparatedLanguages += token; - first = false; - } - } - } - } else if (preferredLanguages == "[]") { - // Handle empty array case - commaSeparatedLanguages = ""; - } else { - // Handle single string value case (e.g., "tam") - // Remove quotes if present and use as-is - if (preferredLanguages.length() >= 2 && preferredLanguages[0] == '"' && preferredLanguages.back() == '"') { - commaSeparatedLanguages = preferredLanguages.substr(1, preferredLanguages.length() - 2); - } else { - commaSeparatedLanguages = preferredLanguages; - } - LOGINFO("Handling single string value: %s", commaSeparatedLanguages.c_str()); - } - - LOGINFO("Converted JSON array to comma-separated: %s", commaSeparatedLanguages.c_str()); - - Core::hresult rc = userSettings->SetPreferredCaptionsLanguages(commaSeparatedLanguages); - - if (rc == Core::ERROR_NONE) { - // Transform response: return_or_error(null, "couldn't set preferred captions languages") - // Success case - return null (no error) - return Core::ERROR_NONE; - } else { - LOGERR("Failed to call SetPreferredCaptionsLanguages on UserSettings COM interface, error: %u", rc); - // Error case - return error - return Core::ERROR_GENERAL; - } - } - - private: - class UserSettingsNotificationHandler: public Exchange::IUserSettings::INotification { - public: - UserSettingsNotificationHandler(UserSettingsDelegate& parent) : mParent(parent),registered(false){} - ~UserSettingsNotificationHandler(){} - - void OnAudioDescriptionChanged(const bool enabled) { - mParent.Dispatch( "accessibility.onaudiodescriptionsettingschanged", ObjectUtils::CreateBooleanJsonString("enabled", enabled)); - } - - void OnPreferredAudioLanguagesChanged(const string& preferredLanguages) { - mParent.Dispatch( "localization.onpreferredaudiolanguageschanged", preferredLanguages); - } - - void OnPresentationLanguageChanged(const string& presentationLanguage) { - - mParent.Dispatch( "localization.onlocalechanged", presentationLanguage); - - // check presentationLanguage is a delimitted string like "en-US" - // add logic to get the "en" if the value is "en-US" - if (presentationLanguage.find('-') != string::npos) { - string language = presentationLanguage.substr(0, presentationLanguage.find('-')); - // Wrap in quotes to make it a valid JSON string - string languageJson = "\"" + language + "\""; - mParent.Dispatch( "localization.onlanguagechanged", languageJson); - } else { - LOGWARN("invalid value=%s set it must be a delimited string like en-US", presentationLanguage.c_str()); - } - } - - void OnCaptionsChanged(const bool enabled) { - mParent.Dispatch( "accessibility.onclosedcaptionssettingschanged", ObjectUtils::CreateBooleanJsonString("enabled", enabled)); - } - - void OnPreferredCaptionsLanguagesChanged(const string& preferredLanguages) { - mParent.Dispatch( "closedcaptions.onpreferredlanguageschanged", preferredLanguages); - } - - void OnPreferredClosedCaptionServiceChanged(const string& service) { - mParent.Dispatch( "OnPreferredClosedCaptionServiceChanged", service); - } - - void OnPrivacyModeChanged(const string& privacyMode) { - mParent.Dispatch( "OnPrivacyModeChanged", privacyMode); - } - - void OnPinControlChanged(const bool pinControl) { - mParent.Dispatch( "OnPinControlChanged", ObjectUtils::BoolToJsonString(pinControl)); - } - - void OnViewingRestrictionsChanged(const string& viewingRestrictions) { - mParent.Dispatch( "OnViewingRestrictionsChanged", viewingRestrictions); - } - - void OnViewingRestrictionsWindowChanged(const string& viewingRestrictionsWindow) { - mParent.Dispatch( "OnViewingRestrictionsWindowChanged", viewingRestrictionsWindow); - } - - void OnLiveWatershedChanged(const bool liveWatershed) { - mParent.Dispatch( "OnLiveWatershedChanged", ObjectUtils::BoolToJsonString(liveWatershed)); - } - - void OnPlaybackWatershedChanged(const bool playbackWatershed) { - mParent.Dispatch( "OnPlaybackWatershedChanged", ObjectUtils::BoolToJsonString(playbackWatershed)); - } - - void OnBlockNotRatedContentChanged(const bool blockNotRatedContent) { - mParent.Dispatch( "OnBlockNotRatedContentChanged", ObjectUtils::BoolToJsonString(blockNotRatedContent)); - } - - void OnPinOnPurchaseChanged(const bool pinOnPurchase) { - mParent.Dispatch( "OnPinOnPurchaseChanged", ObjectUtils::BoolToJsonString(pinOnPurchase)); - } - - void OnHighContrastChanged(const bool enabled) { - mParent.Dispatch( "accessibility.onhighcontrastuichanged", ObjectUtils::BoolToJsonString(enabled)); - } - - void OnVoiceGuidanceChanged(const bool enabled) { - mParent.Dispatch( "accessibility.onvoiceguidancesettingschanged", ObjectUtils::CreateBooleanJsonString("enabled", enabled)); - } - - void OnVoiceGuidanceRateChanged(const double rate) { - mParent.Dispatch( "OnVoiceGuidanceRateChanged", std::to_string(rate)); - } - - void OnVoiceGuidanceHintsChanged(const bool hints) { - mParent.Dispatch( "OnVoiceGuidanceHintsChanged", std::to_string(hints)); - } - - void OnContentPinChanged(const string& contentPin) { - mParent.Dispatch( "OnContentPinChanged", contentPin); - } - - // New Method for Set registered - void SetRegistered(bool state) { - std::lock_guard lock(registerMutex); - registered = state; - } - - // New Method for get registered - bool GetRegistered() { - std::lock_guard lock(registerMutex); - return registered; - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(Exchange::IUserSettings::INotification) - END_INTERFACE_MAP - private: - UserSettingsDelegate& mParent; - bool registered; - std::mutex registerMutex; - - }; - Exchange::IUserSettings *mUserSettings; - PluginHost::IShell* mShell; - Core::Sink mNotificationHandler; - - -}; -#endif diff --git a/FbSettings/tests/CurlCmds.md b/FbSettings/tests/CurlCmds.md deleted file mode 100644 index f7c8add..0000000 --- a/FbSettings/tests/CurlCmds.md +++ /dev/null @@ -1,103 +0,0 @@ -# FbMetrics JSON-RPC cURL Commands - -## Controller: Activate / Deactivate org.rdk.FbMetrics - -### Activate -```bash -curl -d '{"jsonrpc": "2.0","id":122,"method":"Controller.1.activate","params":{"callsign":"org.rdk.FbSettings"}}' http://127.0.0.1:9998/jsonrpc -``` - -### Deactivate -```bash -curl -d '{"jsonrpc": "2.0","id":122,"method":"Controller.1.deactivate","params":{"callsign":"org.rdk.FbSettings"}}' http://127.0.0.1:9998/jsonrpc -``` - ---- - -## Action -```bash -curl -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"100","method":"org.rdk.FbSettings.1.handleAppEventNotifier","params": {"listen": true,"event": "TextToSpeech.Enabled"}}}' http://127.0.0.1:9998/jsonrpc -``` - - -## org.rdk.FbSettings.1: org.rdk.System callsign-derived aliases - -Below are example requests for each of the 13 methods exposed by org.rdk.FbSettings.1. -- For getters/response-only methods, no params are included. -- For methods that require input, an example params object is provided. -- For subscribe methods, the listen parameter is demonstrated. - -1) getDeviceMake -- Tests retrieving the device make (maps to org.rdk.System.getDeviceInfo) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":1,"method":"org.rdk.FbSettings.1.getDeviceMake"}' \ - http://127.0.0.1:9998/jsonrpc -``` - -2) getDeviceName -- Tests retrieving the device friendly name (maps to org.rdk.System.getFriendlyName) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":2,"method":"org.rdk.FbSettings.1.getDeviceName"}' \ - http://127.0.0.1:9998/jsonrpc -``` - -3) setDeviceName -- Tests setting the device friendly name (maps to org.rdk.System.setFriendlyName) -- Example provides a sample name -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":3,"method":"org.rdk.FbSettings.1.setDeviceName","params":{"name":"Living Room"}}' \ - http://127.0.0.1:9998/jsonrpc -``` - -4) getDeviceSku -- Tests retrieving the device SKU (maps to org.rdk.System.getSystemVersions) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":4,"method":"org.rdk.FbSettings.1.getDeviceSku"}' \ - http://127.0.0.1:9998/jsonrpc -``` - -5) getCountryCode -- Tests retrieving the country code (maps to org.rdk.System.getTerritory -> Firebolt country code) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":5,"method":"org.rdk.FbSettings.1.getCountryCode"}' \ - http://127.0.0.1:9998/jsonrpc -``` - -6) setCountryCode -- Tests setting the country code (maps to org.rdk.System.setTerritory) -- Example provides a sample country code (US) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":6,"method":"org.rdk.FbSettings.1.setCountryCode","params":{"countryCode":"US"}}' \ - http://127.0.0.1:9998/jsonrpc -``` - -7) getTimeZone -- Tests retrieving the current timezone (maps to org.rdk.System.getTimeZoneDST) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":8,"method":"org.rdk.FbSettings.1.getTimeZone"}' \ - http://127.0.0.1:9998/jsonrpc -``` - -8) setTimeZone -- Tests setting the current timezone (maps to org.rdk.System.setTimeZoneDST) -- Example provides an illustrative timezone -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":9,"method":"org.rdk.FbSettings.1.setTimeZone","params":{"timeZone":"America/New_York"}}' \ - http://127.0.0.1:9998/jsonrpc -``` - -9) getSecondScreenFriendlyName -- Tests retrieving the second screen friendly name (alias of getDeviceName) -```bash -curl -X POST -H 'Content-Type: application/json' \ - -d '{"jsonrpc":"2.0","id":11,"method":"org.rdk.FbSettings.1.getSecondScreenFriendlyName"}' \ - http://127.0.0.1:9998/jsonrpc -``` diff --git a/LICENSE b/LICENSE index 7212368..f49a4e1 100644 --- a/LICENSE +++ b/LICENSE @@ -198,31 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. - - BSD 2-Clause License - - Copyright - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - + limitations under the License. \ No newline at end of file diff --git a/LifecycleManager/ApplicationContext.cpp b/LifecycleManager/ApplicationContext.cpp deleted file mode 100755 index 4fe41c8..0000000 --- a/LifecycleManager/ApplicationContext.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "ApplicationContext.h" -#include "State.h" - -namespace WPEFramework -{ - namespace Plugin - { - ApplicationLaunchParams::ApplicationLaunchParams(): mAppId(""), mLaunchIntent(""), mLaunchArgs(""), mTargetState(Exchange::ILifecycleManager::LifecycleState::UNLOADED), mRuntimeConfigObject() - { - } - - ApplicationContext::ApplicationContext (std::string appId) - : mPendingStateTransition(false) - , mPendingStates() - , mPendingEventName("") - , mAppInstanceId("") - , mAppId(std::move(appId)) - , mLastLifecycleStateChangeTime{0, 0} - , mActiveSessionId("") - , mTargetLifecycleState() - , mMostRecentIntent("") - , mState(nullptr) - , mStateChangeId(0) -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - , mRequestTime(0) - , mRequestType(REQUEST_TYPE_NONE) -#endif - { - mState = (void*) new UnloadedState(this); - sem_init(&mReachedLoadingStateSemaphore, 0, 0); - sem_init(&mAppReadySemaphore, 0, 0); - sem_init(&mFirstFrameAfterResumeSemaphore, 0, 0); - } - - ApplicationKillParams::ApplicationKillParams(): mForce(false) - { - } - - ApplicationContext::~ApplicationContext() - { - if (nullptr != mState) - { - State* state = (State*)mState; - delete state; - } - mState = nullptr; - } - - void ApplicationContext::setAppInstanceId(std::string& id) - { - mAppInstanceId = id; - } - - void ApplicationContext::setActiveSessionId(std::string& id) - { - mActiveSessionId = id; - } - - void ApplicationContext::setMostRecentIntent(const std::string& intent) - { - mMostRecentIntent = intent; - } - - void ApplicationContext::setLastLifecycleStateChangeTime(timespec changeTime) - { - mLastLifecycleStateChangeTime = changeTime; - } - - void ApplicationContext::setState(void* state) - { - mState = state; - } - - void ApplicationContext::setTargetLifecycleState(Exchange::ILifecycleManager::LifecycleState state) - { - mTargetLifecycleState = state; - } - - void ApplicationContext::setStateChangeId(uint32_t id) - { - mStateChangeId = id; - } - - void ApplicationContext::setApplicationLaunchParams(const string& appId, const string& launchIntent, const string& launchArgs, Exchange::ILifecycleManager::LifecycleState targetState, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject) - { - mLaunchParams.mAppId = appId; - mLaunchParams.mLaunchIntent = launchIntent; - mLaunchParams.mLaunchArgs = launchArgs; - mLaunchParams.mTargetState = targetState; - mLaunchParams.mRuntimeConfigObject = runtimeConfigObject; - } - - void ApplicationContext::setApplicationKillParams(bool force) - { - mKillParams.mForce = force; - } - - void ApplicationContext::setRequestTime(time_t requestTime) - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - mRequestTime = requestTime; -#endif - } - void ApplicationContext::setRequestType(RequestType requestType) - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - mRequestType = requestType; -#endif - } - - - std::string ApplicationContext::getAppId() - { - return mAppId; - } - - std::string ApplicationContext::getAppInstanceId() - { - return mAppInstanceId; - } - - Exchange::ILifecycleManager::LifecycleState ApplicationContext::getCurrentLifecycleState() - { - State* state = (State*)mState; - return state->getValue(); - } - - timespec ApplicationContext::getLastLifecycleStateChangeTime() - { - return mLastLifecycleStateChangeTime; - } - - std::string ApplicationContext::getActiveSessionId() - { - return mActiveSessionId; - } - - Exchange::ILifecycleManager::LifecycleState ApplicationContext::getTargetLifecycleState() - { - return mTargetLifecycleState; - } - - std::string ApplicationContext::getMostRecentIntent() - { - return mMostRecentIntent; - } - - void* ApplicationContext::getState() - { - return mState; - } - - uint32_t ApplicationContext::getStateChangeId() - { - return mStateChangeId; - } - - ApplicationLaunchParams& ApplicationContext::getApplicationLaunchParams() - { - return mLaunchParams; - } - - ApplicationKillParams& ApplicationContext::getApplicationKillParams() - { - return mKillParams; - } - - time_t ApplicationContext::getRequestTime() - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - return mRequestTime; -#else - return 0; -#endif - } - - RequestType ApplicationContext::getRequestType() - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - return mRequestType; -#else - return REQUEST_TYPE_NONE; -#endif - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/ApplicationContext.h b/LifecycleManager/ApplicationContext.h deleted file mode 100755 index 9a76ab3..0000000 --- a/LifecycleManager/ApplicationContext.h +++ /dev/null @@ -1,117 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - struct ApplicationLaunchParams - { - ApplicationLaunchParams(); - string mAppId; - string mLaunchIntent; - string mLaunchArgs; - Exchange::ILifecycleManager::LifecycleState mTargetState; - WPEFramework::Exchange::RuntimeConfig mRuntimeConfigObject; - }; - - struct ApplicationKillParams - { - ApplicationKillParams(); - bool mForce; - }; - - enum RequestType { - REQUEST_TYPE_NONE, - REQUEST_TYPE_LAUNCH, - REQUEST_TYPE_PAUSE, - REQUEST_TYPE_SUSPEND, - REQUEST_TYPE_RESUME, - REQUEST_TYPE_HIBERNATE, - REQUEST_TYPE_WAKE, - REQUEST_TYPE_TERMINATE - }; - - class ApplicationContext - { - public: - ApplicationContext (std::string appId); - virtual ~ApplicationContext (); - - void setAppInstanceId(std::string& id); - void setActiveSessionId(std::string& id); - void setMostRecentIntent(const std::string& intent); - void setLastLifecycleStateChangeTime(timespec changeTime); - void setState(void* state); - void setTargetLifecycleState(Exchange::ILifecycleManager::LifecycleState state); - void setStateChangeId(uint32_t id); - void setApplicationLaunchParams(const string& appId, const string& launchIntent, const string& launchArgs, Exchange::ILifecycleManager::LifecycleState targetState, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject); - void setApplicationKillParams(bool force); - void setRequestTime(time_t requestTime); - void setRequestType(RequestType requestType); - - void* getState(); - std::string getAppId(); - std::string getAppInstanceId(); - Exchange::ILifecycleManager::LifecycleState getCurrentLifecycleState(); - timespec getLastLifecycleStateChangeTime(); - std::string getActiveSessionId(); - Exchange::ILifecycleManager::LifecycleState getTargetLifecycleState(); - std::string getMostRecentIntent(); - uint32_t getStateChangeId(); - ApplicationLaunchParams& getApplicationLaunchParams(); - ApplicationKillParams& getApplicationKillParams(); - time_t getRequestTime(); - RequestType getRequestType(); - - sem_t mReachedLoadingStateSemaphore; - sem_t mAppReadySemaphore; - sem_t mFirstFrameAfterResumeSemaphore; - bool mPendingStateTransition; - std::vector mPendingStates; - Exchange::ILifecycleManager::LifecycleState mPendingOldState; - std::string mPendingEventName; - - private: - std::string mAppInstanceId; - std::string mAppId; - timespec mLastLifecycleStateChangeTime; - std::string mActiveSessionId; - Exchange::ILifecycleManager::LifecycleState mTargetLifecycleState; - std::string mMostRecentIntent; - void* mState; - uint32_t mStateChangeId; - ApplicationLaunchParams mLaunchParams; - ApplicationKillParams mKillParams; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - time_t mRequestTime; - RequestType mRequestType; -#endif - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/CHANGELOG.md b/LifecycleManager/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/LifecycleManager/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/LifecycleManager/CMakeLists.txt b/LifecycleManager/CMakeLists.txt deleted file mode 100755 index f9ce953..0000000 --- a/LifecycleManager/CMakeLists.txt +++ /dev/null @@ -1,86 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME LifecycleManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(PLUGIN_LIFECYCLE_MANAGER_MODE "Local" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_LIFECYCLE_MANAGER_AUTOSTART false CACHE STRING "Automatically start LifecycleManager plugin") -set(PLUGIN_LIFECYCLE_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_LIFECYCLE_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start LifecycleManager plugin") -option(AIMANAGERS_TELEMETRY_METRICS_SUPPORT "AIMANAGERS_TELEMETRY_METRICS_SUPPORT" OFF) - -add_definitions(-DLIFECYCLE_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DLIFECYCLE_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DLIFECYCLE_MANAGER_API_VERSION_NUMBER_PATCH=0) - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -set(PLUGIN_LIFECYCLE_MANAGER_SOURCES - LifecycleManager.cpp - LifecycleManagerImplementation.cpp - Module.cpp - ApplicationContext.cpp - RequestHandler.cpp - RuntimeManagerHandler.cpp - WindowManagerHandler.cpp - State.cpp - StateHandler.cpp - StateTransitionHandler.cpp) - -if (AIMANAGERS_TELEMETRY_METRICS_SUPPORT) -list( APPEND PLUGIN_LIFECYCLE_MANAGER_SOURCES - LifecycleManagerTelemetryReporting.cpp -) -add_definitions(-DENABLE_AIMANAGERS_TELEMETRY_METRICS) -endif (AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - -add_library(${MODULE_NAME} SHARED - ${PLUGIN_LIFECYCLE_MANAGER_SOURCES} -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(LifecycleManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -option(ENABLE_UNIT_TESTS "Enable unit tests" OFF) -if(ENABLE_UNIT_TESTS) - target_compile_definitions(${MODULE_NAME} PRIVATE UNIT_TEST) -endif() - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -include_directories(../helpers) - -set(LIFECYCLE_MANAGER_INCLUDES $ENV{LIFECYCLE_MANAGER_INCLUDES}) -separate_arguments(LIFECYCLE_MANAGER_INCLUDES) -include_directories(BEFORE ${LIFECYCLE_MANAGER_INCLUDES}) - -write_config(${PLUGIN_NAME}) diff --git a/LifecycleManager/IEventHandler.h b/LifecycleManager/IEventHandler.h deleted file mode 100644 index 9b1de44..0000000 --- a/LifecycleManager/IEventHandler.h +++ /dev/null @@ -1,38 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - class IEventHandler - { - public: - virtual void onRuntimeManagerEvent(JsonObject& data) = 0; - virtual void onWindowManagerEvent(JsonObject& data) = 0; - virtual void onRippleEvent(std::string name, JsonObject& data) = 0; - virtual void onStateChangeEvent(JsonObject& data) = 0; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/LifecycleManager.conf.in b/LifecycleManager/LifecycleManager.conf.in deleted file mode 100644 index 8fc4dee..0000000 --- a/LifecycleManager/LifecycleManager.conf.in +++ /dev/null @@ -1,3 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.LifecycleManager" -autostart = "false" diff --git a/LifecycleManager/LifecycleManager.config b/LifecycleManager/LifecycleManager.config deleted file mode 100644 index 0fb16f6..0000000 --- a/LifecycleManager/LifecycleManager.config +++ /dev/null @@ -1,3 +0,0 @@ -set (autostart false) -set (preconditions Platform) -set (callsign "org.rdk.LifecycleManager") diff --git a/LifecycleManager/LifecycleManager.cpp b/LifecycleManager/LifecycleManager.cpp deleted file mode 100644 index b53cfde..0000000 --- a/LifecycleManager/LifecycleManager.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "LifecycleManager.h" -#include - -const string WPEFramework::Plugin::LifecycleManager::SERVICE_NAME = "org.rdk.LifecycleManager"; - -namespace WPEFramework -{ - namespace { - - static Plugin::Metadata metadata( - /* Version (Major, Minor, Patch) */ - LIFECYCLE_MANAGER_API_VERSION_NUMBER_MAJOR, LIFECYCLE_MANAGER_API_VERSION_NUMBER_MINOR, LIFECYCLE_MANAGER_API_VERSION_NUMBER_PATCH, - /* Preconditions */ - {}, - /* Terminations */ - {}, - /* Controls */ - {} - ); - } - - namespace Plugin - { - - SERVICE_REGISTRATION(LifecycleManager, LIFECYCLE_MANAGER_API_VERSION_NUMBER_MAJOR, LIFECYCLE_MANAGER_API_VERSION_NUMBER_MINOR, LIFECYCLE_MANAGER_API_VERSION_NUMBER_PATCH); - - LifecycleManager* LifecycleManager::sInstance = nullptr; - - LifecycleManager::LifecycleManager(): _service(nullptr), mConnectionId(0), mLifecycleManagerImplementation(nullptr), mLifecycleManagerState(nullptr), mLifecycleManagerStateNotification(this) - { - SYSLOG(Logging::Startup, (_T("LifecycleManager Constructor"))); - LifecycleManager::sInstance = this; - } - - LifecycleManager::~LifecycleManager() - { - SYSLOG(Logging::Startup, (_T("LifecycleManager Destructor"))); - LifecycleManager::sInstance = nullptr; - mLifecycleManagerState = nullptr; - mLifecycleManagerImplementation = nullptr; - } - - const string LifecycleManager::Initialize(PluginHost::IShell* service ) - { - //uint32_t result = Core::ERROR_GENERAL; - string retStatus = ""; - ASSERT(nullptr != service); - ASSERT(0 == mConnectionId); - ASSERT(nullptr == _service); - SYSLOG(Logging::Startup, (_T("LifecycleManager::Initialize: PID=%u"), getpid())); - //{ - // SYSLOG(Logging::Startup, (_T("LifecycleManager::Initialize: service is not valid"))); - // retStatus = _T("LifecycleManager plugin could not be initialised"); - //} - _service = service; - _service->AddRef(); - mLifecycleManagerImplementation = _service->Root(mConnectionId, 5000, _T("LifecycleManagerImplementation")); - if (nullptr == mLifecycleManagerImplementation) - { - retStatus = "error starting lifecyclemanager"; - return retStatus; - } - auto lifeCycleManagerConfig = mLifecycleManagerImplementation->QueryInterface(); - if (lifeCycleManagerConfig != nullptr) - { - lifeCycleManagerConfig->Configure(service); - lifeCycleManagerConfig->Release(); - } - mLifecycleManagerState = mLifecycleManagerImplementation->QueryInterface(); - ASSERT(mLifecycleManagerState != nullptr); - mLifecycleManagerState->Register(&mLifecycleManagerStateNotification); - Exchange::JLifecycleManagerState::Register(*this, mLifecycleManagerState); - - return retStatus; - } - - void LifecycleManager::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Startup, (_T("LifecycleManager::Deinitialize: PID=%u"), getpid())); - ASSERT(_service == service); - if (mLifecycleManagerState != nullptr) - { - mLifecycleManagerState->Unregister(&mLifecycleManagerStateNotification); - Exchange::JLifecycleManagerState::Unregister(*this); - mLifecycleManagerState->Release(); - mLifecycleManagerState = nullptr; - } - - if (nullptr != mLifecycleManagerImplementation) - { - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mLifecycleManagerImplementation->Release(); - mLifecycleManagerImplementation = nullptr; - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - mConnectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("LifecycleManager de-initialised")))); - } - - string LifecycleManager::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/LifecycleManager.h b/LifecycleManager/LifecycleManager.h deleted file mode 100644 index e5c347f..0000000 --- a/LifecycleManager/LifecycleManager.h +++ /dev/null @@ -1,118 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework -{ - namespace Plugin - { - class LifecycleManager : public PluginHost::IPlugin, public PluginHost::JSONRPC - { - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::ILifecycleManagerState::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(LifecycleManager* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::ILifecycleManagerState::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - LOGINFO("LifecycleManagerState Notification Activated"); - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - LOGINFO("LifecycleManagerState Notification Deactivated"); - } - - void OnAppLifecycleStateChanged(const string& appId, - const string& appInstanceId, - const Exchange::ILifecycleManager::LifecycleState oldState, - const Exchange::ILifecycleManager::LifecycleState newState, - const string& navigationIntent) override - { - LOGINFO("LifecycleManagerState onAppLifecycleStateChanged"); - Exchange::JLifecycleManagerState::Event::OnAppLifecycleStateChanged(_parent, appId,appInstanceId,oldState, newState, navigationIntent); - } - - private: - LifecycleManager& _parent; - }; - - public: - LifecycleManager(const LifecycleManager&) = delete; - LifecycleManager& operator=(const LifecycleManager&) = delete; - - LifecycleManager(); - virtual ~LifecycleManager(); - - BEGIN_INTERFACE_MAP(LifecycleManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::ILifecycleManager, mLifecycleManagerImplementation) - INTERFACE_AGGREGATE(Exchange::ILifecycleManagerState, mLifecycleManagerState) - END_INTERFACE_MAP - - /* IPlugin methods */ - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static LifecycleManager* sInstance; - - private: /* members */ - PluginHost::IShell* _service{}; - uint32_t mConnectionId; - Exchange::ILifecycleManager* mLifecycleManagerImplementation; - Exchange::ILifecycleManagerState* mLifecycleManagerState; - Core::Sink mLifecycleManagerStateNotification; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/LifecycleManagerImplementation.cpp b/LifecycleManager/LifecycleManagerImplementation.cpp deleted file mode 100755 index 8a0cea9..0000000 --- a/LifecycleManager/LifecycleManagerImplementation.cpp +++ /dev/null @@ -1,771 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "LifecycleManagerImplementation.h" -#include "RequestHandler.h" -#include "UtilsJsonRpc.h" -#include -#include -#include -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include "LifecycleManagerTelemetryReporting.h" -#endif - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(LifecycleManagerImplementation, 1, 0); - - LifecycleManagerImplementation::LifecycleManagerImplementation(): mLifecycleManagerNotification(), mLifecycleManagerStateNotification(), mLoadedApplications(), mService(nullptr) - { - LOGINFO("Create LifecycleManagerImplementation Instance"); - } - - LifecycleManagerImplementation::~LifecycleManagerImplementation() - { - LOGINFO("Delete LifecycleManagerImplementation Instance"); - terminate(); - } - - bool LifecycleManagerImplementation::initialize(PluginHost::IShell* service) - { - bool ret = RequestHandler::getInstance()->initialize(service, this); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - LifecycleManagerTelemetryReporting::getInstance().initialize(service); -#endif - return ret; - } - - void LifecycleManagerImplementation::terminate() - { - try - { - RequestHandler::getInstance()->terminate(); - } - catch(const std::exception& e) - { - LOGERR("Exception in LifecycleManagerImplementation::terminate: %s", e.what()); - } - if (mService != nullptr) - { - mService->Release(); - mService = nullptr; - } - } - - Core::hresult LifecycleManagerImplementation::Register(Exchange::ILifecycleManager::INotification *notification) - { - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mLifecycleManagerNotification.begin(), mLifecycleManagerNotification.end(), notification) == mLifecycleManagerNotification.end()) - { - LOGINFO("Register notification"); - mLifecycleManagerNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult LifecycleManagerImplementation::Unregister(Exchange::ILifecycleManager::INotification *notification ) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mLifecycleManagerNotification.begin(), mLifecycleManagerNotification.end(), notification); - if (itr != mLifecycleManagerNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mLifecycleManagerNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; - } - - void LifecycleManagerImplementation::dispatchEvent(EventNames event, const JsonValue ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void LifecycleManagerImplementation::Dispatch(EventNames event, const JsonValue params) - { - JsonObject obj = params.Object(); - - //below is for ILifecycleManager notification - string appId(obj["appId"].String()); - string errorReason(obj["errorReason"].String()); - uint32_t newLifecycleState(obj["newLifecycleState"].Number()); - - //below is additional for ILifecycleManagerState notification - string appInstanceId(obj["appInstanceId"].String()); - uint32_t oldLifecycleState(obj["oldLifecycleState"].Number()); - string navigationIntent(obj["navigationIntent"].String()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - ApplicationContext* context = getContext("", appId); -#endif - - mAdminLock.Lock(); - - std::list::const_iterator index(mLifecycleManagerNotification.begin()); - std::list::const_iterator stateNotificationIndex(mLifecycleManagerStateNotification.begin()); - - switch(event) - { - case LIFECYCLE_MANAGER_EVENT_APPSTATECHANGED: -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - LifecycleManagerTelemetryReporting::getInstance().reportTelemetryDataOnStateChange(context, obj); -#endif - handleStateChangeEvent(obj); - while (index != mLifecycleManagerNotification.end()) - { - (*index)->OnAppStateChanged(appId, (LifecycleState)newLifecycleState, errorReason); - ++index; - } - while (stateNotificationIndex != mLifecycleManagerStateNotification.end()) - { - (*stateNotificationIndex)->OnAppLifecycleStateChanged(appId, appInstanceId, (LifecycleState)oldLifecycleState, (LifecycleState)newLifecycleState, navigationIntent); - ++stateNotificationIndex; - } - break; - case LIFECYCLE_MANAGER_EVENT_RUNTIME: - handleRuntimeManagerEvent(obj); - break; - case LIFECYCLE_MANAGER_EVENT_WINDOW: - handleWindowManagerEvent(obj); - break; - case LIFECYCLE_MANAGER_EVENT_ONFAILURE: - while (index != mLifecycleManagerNotification.end()) - { - (*index)->OnAppStateChanged(appId, (LifecycleState)newLifecycleState, errorReason); - ++index; - } - break; - default: - LOGWARN("Event[%u] not handled", event); - break; - } - - mAdminLock.Unlock(); - } - - Core::hresult LifecycleManagerImplementation::GetLoadedApps(const bool verbose, string& apps) - { - Core::hresult status = Core::ERROR_NONE; - JsonArray appsInformation; - std::list::iterator iter = mLoadedApplications.end(); - for (iter = mLoadedApplications.begin(); iter != mLoadedApplications.end(); iter++) - { - if (nullptr != *iter) - { - JsonObject appData; - ApplicationContext* context = (*iter); - appData["appInstanceID"] = context->getAppInstanceId(); - appData["appId"] = context->getAppId(); - struct timespec lastStateChangeTime = context->getLastLifecycleStateChangeTime(); - char timeData[200]; - char timeDataExpanded[1000]; - memset(timeData, 0, sizeof(timeData)); - memset(timeDataExpanded, 0, sizeof(timeDataExpanded)); - strftime(timeData, sizeof timeData, "%D %T", gmtime(&lastStateChangeTime.tv_sec)); - sprintf(timeDataExpanded, "%s.%09ld", timeData, lastStateChangeTime.tv_nsec); - appData["lifecycleState"] = (uint32_t) context->getCurrentLifecycleState(); - appData["timeOfLastLifecycleStateChange"] = string(timeDataExpanded); - appData["activeSessionId"] = context->getActiveSessionId(); - appData["targetLifecycleState"] = (uint32_t) context->getTargetLifecycleState(); - appData["mostRecentIntent"] = context->getMostRecentIntent(); - if (verbose) - { - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - string runtimeStats(""); - bool runtimeStatsResult = runtimeManagerHandler->getRuntimeStats(context->getAppInstanceId(), runtimeStats); - if (true == runtimeStatsResult) - { - appData["runtimeStats"] = runtimeStats; - } - else - { - printf("unable to get runtime status of application\n"); - fflush(stdout); - } - } - } - appsInformation.Add(appData); - } - } - appsInformation.ToString(apps); - return status; - } - - Core::hresult LifecycleManagerImplementation::IsAppLoaded(const string& appId, bool& loaded) const - { - Core::hresult status = Core::ERROR_NONE; - loaded = false; - ApplicationContext* context = getContext("", appId); - if (nullptr != context) - { - loaded = true; - } - return status; - } - - Core::hresult LifecycleManagerImplementation::SpawnApp(const string& appId, const string& launchIntent, const LifecycleState targetLifecycleState, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, const string& launchArgs, string& appInstanceId, string& errorReason, bool& success) - { - // Launches an app. This will be an asynchronous call. - // Notifies appropriate API Gateway when an app is about to be loaded - // Lifecycle manager will create the appInstanceId once the app is loaded. Ripple is responsible for creating a token. - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext("", appId); - bool firstLaunch = false; - time_t requestTime = 0; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - requestTime = LifecycleManagerTelemetryReporting::getInstance().getCurrentTimestamp(); -#endif - mAdminLock.Lock(); - if (nullptr == context) - { - context = new ApplicationContext(appId); - context->setApplicationLaunchParams(appId, launchIntent, launchArgs, targetLifecycleState, runtimeConfigObject); - mLoadedApplications.push_back(context); - firstLaunch = true; - } - context->setRequestTime(requestTime); - context->setRequestType(REQUEST_TYPE_LAUNCH); - context->setTargetLifecycleState(targetLifecycleState); - context->setMostRecentIntent(launchIntent); - success = RequestHandler::getInstance()->launch(context, launchIntent, targetLifecycleState, errorReason); - if (!success) - { - status = Core::ERROR_GENERAL; - } - else - { - if (firstLaunch) - { - sem_wait(&context->mReachedLoadingStateSemaphore); - } - appInstanceId = context->getAppInstanceId(); - } - mAdminLock.Unlock(); - return status; - } - - Core::hresult LifecycleManagerImplementation::SetTargetAppState(const string& appInstanceId, const LifecycleState targetLifecycleState, const string& launchIntent) - { - // Moves a currently loaded app between states - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext(appInstanceId, ""); - time_t requestTime = 0; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - requestTime = LifecycleManagerTelemetryReporting::getInstance().getCurrentTimestamp(); -#endif - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - return status; - } - mAdminLock.Lock(); - switch(targetLifecycleState) - { - case Exchange::ILifecycleManager::LifecycleState::PAUSED: //before SUSPEND or HIBERNATE app will be PAUSED - context->setRequestTime(requestTime); - context->setRequestType(REQUEST_TYPE_PAUSE); - break; - case Exchange::ILifecycleManager::LifecycleState::SUSPENDED: - context->setRequestType(REQUEST_TYPE_SUSPEND); - break; - case Exchange::ILifecycleManager::LifecycleState::HIBERNATED: - context->setRequestType(REQUEST_TYPE_HIBERNATE); - break; - case Exchange::ILifecycleManager::LifecycleState::ACTIVE: - context->setRequestTime(requestTime); - context->setRequestType(REQUEST_TYPE_RESUME); - break; - default: - LOGERR("targetLifecycleState is invalid"); - break; - } - string errorReason(""); - context->setTargetLifecycleState(targetLifecycleState); - context->setMostRecentIntent(launchIntent); - - bool success = RequestHandler::getInstance()->updateState(context, targetLifecycleState, errorReason); - mAdminLock.Unlock(); - if (false == success) - { - status = Core::ERROR_GENERAL; - return status; - } - return status; - } - - Core::hresult LifecycleManagerImplementation::UnloadApp(const string& appInstanceId, string& errorReason, bool& success) - { - // Begins a graceful shutdown of the app. Moves the app through the lifecycle states till it ultimately ends in app container being terminated. - // This is an asynchronous call, clients should use the onAppStateChange event to determine when the app is actually terminated. - // This moves an app to the unloaded state - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext(appInstanceId, ""); - time_t requestTime = 0; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - requestTime = LifecycleManagerTelemetryReporting::getInstance().getCurrentTimestamp(); -#endif - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - success = false; - return status; - } - mAdminLock.Lock(); - if(REQUEST_TYPE_PAUSE != context->getRequestType()) //If request through AppManager closeApp, requestTime is already set - { - context->setRequestTime(requestTime); - } - context->setRequestType(REQUEST_TYPE_TERMINATE); - context->setTargetLifecycleState(Exchange::ILifecycleManager::LifecycleState::TERMINATING); - context->setApplicationKillParams(false); - - success = RequestHandler::getInstance()->terminate(context, false, errorReason); - if (!success) - { - status = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - return status; - } - - Core::hresult LifecycleManagerImplementation::KillApp(const string& appInstanceId, string& errorReason, bool& success) - { - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext(appInstanceId, ""); - time_t requestTime =0; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - requestTime = LifecycleManagerTelemetryReporting::getInstance().getCurrentTimestamp(); -#endif - - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - success = false; - return status; - } - mAdminLock.Lock(); - context->setRequestTime(requestTime); - context->setRequestType(REQUEST_TYPE_TERMINATE); - context->setTargetLifecycleState(Exchange::ILifecycleManager::LifecycleState::TERMINATING); - context->setApplicationKillParams(true); - success = RequestHandler::getInstance()->terminate(context, true, errorReason); - mAdminLock.Unlock(); - return status; - } - - Core::hresult LifecycleManagerImplementation::SendIntentToActiveApp(const string& appInstanceId, const string& intent, string& errorReason, bool& success) - { - // Sends arguments to a launched app. This API is used for sending deeplinks to an application. This can only be sent to an active app. This method does nothing if the app is not active, and an errorReason is returned. - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext(appInstanceId, ""); - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - success = false; - return status; - } - - // sending intent is not valid for non-active application - if (Exchange::ILifecycleManager::LifecycleState::ACTIVE != context->getCurrentLifecycleState()) - { - printf("Failed to send intent to non-active app [%s] \n", appInstanceId.c_str()); - fflush(stdout); - status = Core::ERROR_GENERAL; - success = false; - errorReason = "application is not active"; - return status; - } - - JsonObject eventData; - eventData["appId"] = context->getAppId(); - eventData["appInstanceId"] = context->getAppInstanceId(); - eventData["oldLifecycleState"] = (uint32_t)Exchange::ILifecycleManager::LifecycleState::ACTIVE; - eventData["newLifecycleState"] = (uint32_t)Exchange::ILifecycleManager::LifecycleState::ACTIVE; - eventData["navigationIntent"] = intent; - eventData["errorReason"] = ""; - dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_APPSTATECHANGED, eventData); - status = Core::ERROR_NONE; - return status; - } - - Core::hresult LifecycleManagerImplementation::Register(Exchange::ILifecycleManagerState::INotification *notification) - { - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mLifecycleManagerStateNotification.begin(), mLifecycleManagerStateNotification.end(), notification) == mLifecycleManagerStateNotification.end()) - { - LOGINFO("Register notification"); - mLifecycleManagerStateNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult LifecycleManagerImplementation::Unregister(Exchange::ILifecycleManagerState::INotification *notification ) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mLifecycleManagerStateNotification.begin(), mLifecycleManagerStateNotification.end(), notification); - if (itr != mLifecycleManagerStateNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mLifecycleManagerStateNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; - } - - Core::hresult LifecycleManagerImplementation::AppReady(const string& appId) - { - Core::hresult status = Core::ERROR_NONE; - printf("[LifecycleManager] Received appReady event for [%s] \n", appId.c_str()); - fflush(stdout); - ApplicationContext* context = getContext("", appId); - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - return status; - } - sem_post(&context->mAppReadySemaphore); - return status; - } - - Core::hresult LifecycleManagerImplementation::StateChangeComplete(const string& appId, const uint32_t stateChangedId, const bool success) - { - Core::hresult status = Core::ERROR_NONE; - return status; - } - - Core::hresult LifecycleManagerImplementation::CloseApp(const string& appId, const Exchange::ILifecycleManagerState::AppCloseReason closeReason) - { - Core::hresult status = Core::ERROR_NONE; - ApplicationContext* context = getContext("", appId); - if (nullptr == context) - { - status = Core::ERROR_GENERAL; - return status; - } - bool success = false; - bool activate = false; - string errorReason(""), appInstanceId(""); - status = KillApp(context->getAppInstanceId(), errorReason, success); - if (status != Core::ERROR_NONE) - { - printf("Failed to close the app [%s]\n", appId.c_str()); - fflush(stdout); - return status; - } - if ((closeReason != KILL_AND_RUN) && (closeReason != KILL_AND_ACTIVATE)) - { - return status; - } - activate = (closeReason == KILL_AND_ACTIVATE); - - ApplicationLaunchParams& launchParams = context->getApplicationLaunchParams(); - status = SpawnApp(launchParams.mAppId, launchParams.mLaunchIntent, activate?Exchange::ILifecycleManager::LifecycleState::ACTIVE:Exchange::ILifecycleManager::LifecycleState::PAUSED, launchParams.mRuntimeConfigObject, launchParams.mLaunchArgs, appInstanceId, errorReason, success); - return status; - } - - uint32_t LifecycleManagerImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_GENERAL; - if (service != nullptr) - { - mService = service; - mService->AddRef(); - } - else - { - LOGERR("service is null \n"); - return result; - } - bool ret = initialize(service); - if (ret) - { - result = Core::ERROR_NONE; - } - else - { - printf("unable to configure lifecyclemanager \n"); - fflush(stdout); - } - return result; - } - - ApplicationContext* LifecycleManagerImplementation::getContext(const string& appInstanceId, const string& appId) const - { - ApplicationContext* context = nullptr; - std::list::const_iterator iter = mLoadedApplications.end(); - for (iter = mLoadedApplications.begin(); iter != mLoadedApplications.end(); iter++) - { - if (nullptr != *iter) - { - if ((!appInstanceId.empty()) && ((*iter)->getAppInstanceId() == appInstanceId)) - { - context = *iter; - break; - } - else if ((!appId.empty()) && ((*iter)->getAppId() == appId)) - { - context = *iter; - break; - } - } - } - return context; - } - - void LifecycleManagerImplementation::onRuntimeManagerEvent(JsonObject& data) - { - dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_RUNTIME, data); - } - - void LifecycleManagerImplementation::onWindowManagerEvent(JsonObject& data) - { - dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_WINDOW, data); - } - - void LifecycleManagerImplementation::onRippleEvent(string name, JsonObject& data) - { - //mLifecycleManager->dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_APPSTATECHANGED, JsonValue(minutes)); - } - - void LifecycleManagerImplementation::onStateChangeEvent(JsonObject& data) - { - dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_APPSTATECHANGED, data); - } - - void LifecycleManagerImplementation::handleRuntimeManagerEvent(const JsonObject &data) - { - string eventName = data["name"]; - if (eventName.compare("onTerminated") == 0) - { - LOGINFO("Received onterminated event from runtime manager"); - string appInstanceId = data["appInstanceId"]; - ApplicationContext* context = getContext(appInstanceId, ""); - if (nullptr == context) - { - LOGERR("Received termination event for app which is not available"); - } - else - { - LOGINFO("Received state change event for app Onterminated event "); - //check if unexpected termination - if (context->getCurrentLifecycleState() != Exchange::ILifecycleManager::LifecycleState::TERMINATING) - { - LOGWARN("Container has terminated unexpectedly for app[%s] ", appInstanceId.c_str()); - LOGWARN("Unloading app [%s] - [%s]", context->getAppId().c_str(), appInstanceId.c_str()); - std::string terminateError=""; - std::string updateError=""; - bool terminated = false; - bool stateUpdated = false; - context->setRequestType(REQUEST_TYPE_TERMINATE); - context->setTargetLifecycleState(Exchange::ILifecycleManager::LifecycleState::TERMINATING); - context->setApplicationKillParams(false); - - terminated = RequestHandler::getInstance()->terminate(context, false, terminateError); - stateUpdated = RequestHandler::getInstance()->updateState(context, context->getTargetLifecycleState(), updateError); - if(terminated && stateUpdated) - { - LOGINFO("Successfully handled unexpected container termination for app[%s] ", appInstanceId.c_str()); - LOGINFO("Successfully triggered unload for app[%s]", appInstanceId.c_str()); - } - else - { - LOGERR("Failed to handle unexpected termination for app[%s] terminateSuccess[%d] updateStateSuccess[%d] terminateError[%s] updateError[%s]", appInstanceId.c_str(), terminated, stateUpdated, terminateError.c_str(), updateError.c_str()); - } - } - else - { - addStateTransitionRequest(context, "onAppTerminating"); - } - } - } - else if (eventName.compare("onStateChanged") == 0) - { - string appInstanceId = data["appInstanceId"]; - uint32_t runtimeState = data["state"].Number(); - if (Exchange::IRuntimeManager::RuntimeState::RUNTIME_STATE_RUNNING == runtimeState) - { - ApplicationContext* context = getContext(appInstanceId, ""); - if (nullptr == context) - { - LOGERR("Received state change event for app which is not available"); - } - else - { - LOGINFO("Received state change event for app which is available ie running"); - addStateTransitionRequest(context, "onAppRunning"); - } - } - // state change to TERMINATING is ignored as it is handled in onTerminated - } - else if (eventName.compare("onFailure") == 0) - { - string appInstanceId = data["appInstanceId"]; - string errorCode = data["errorCode"]; - LOGERR("Received container failure event from runtime manager for app[%s] error[%s]", appInstanceId.c_str(), errorCode.c_str()); - notifyOnFailure(appInstanceId, errorCode); - } - else if (eventName.compare("onStarted") == 0) - { - string appInstanceId = data["appInstanceId"]; - LOGINFO("Received container started event from runtime manager for app[%s]", appInstanceId.c_str()); - } - } - - void LifecycleManagerImplementation::notifyOnFailure(const string& appInstanceId, const string& errorCode) - { - string appId = ""; - JsonObject eventData; - ApplicationContext* context = getContext(appInstanceId, ""); - if (nullptr != context) - { - appId = context->getAppId(); - } - eventData["appId"] = appId; - eventData["appInstanceId"] = appInstanceId; - eventData["newLifecycleState"] = static_cast(Exchange::ILifecycleManager::LifecycleState::UNLOADED); - eventData["errorReason"] = errorCode; - dispatchEvent(LifecycleManagerImplementation::EventNames::LIFECYCLE_MANAGER_EVENT_ONFAILURE, eventData); - LOGINFO("Notify error event for appId[%s] appInstanceId[%s] error[%s]", appId.c_str(), appInstanceId.c_str(), errorCode.c_str()); - } - - void LifecycleManagerImplementation::handleStateChangeEvent(const JsonObject &data) - { - string appInstanceId = data["appInstanceId"]; - uint32_t stateInput = data["newLifecycleState"].Number(); - Exchange::ILifecycleManager::LifecycleState state = (Exchange::ILifecycleManager::LifecycleState) stateInput; - if (state != Exchange::ILifecycleManager::LifecycleState::UNLOADED) - { - return; - } - ApplicationContext* context = nullptr; - std::list::iterator iter = mLoadedApplications.end(); - for (iter = mLoadedApplications.begin(); iter != mLoadedApplications.end(); iter++) - { - context = *iter; - if (nullptr == context) - { - continue; - } - if (context->getAppInstanceId() == appInstanceId) - { - break; - } - } - if ((iter != mLoadedApplications.end()) && (nullptr != context)) - { - delete context; - mLoadedApplications.erase(iter); - } - } - - - void LifecycleManagerImplementation::handleWindowManagerEvent(const JsonObject &data) - { - string eventName = data["name"]; - if (eventName.compare("onUserInactivity") == 0) - { - printf("Received onUserInactivity event from window manager \n"); - fflush(stdout); - } - else if (eventName.compare("onDisconnect") == 0) - { - printf("Received onDisconnect event from window manager \n"); - fflush(stdout); - } - else if (eventName.compare("onReady") == 0) - { - printf("Received onReady event from window manager \n"); - fflush(stdout); - std::string appInstanceId = data["appInstanceId"]; - ApplicationContext* context = getContext(appInstanceId, ""); - if (nullptr != context) - { - addStateTransitionRequest(context, "onFirstFrame"); - } - } - } - - void LifecycleManagerImplementation::addStateTransitionRequest(ApplicationContext* context, std::string event) - { - if (context->mPendingStateTransition && (0 == context->mPendingEventName.compare(event))) - { - std::string errorReason(""); - bool success = RequestHandler::getInstance()->updateState(context, context->getTargetLifecycleState(), errorReason); - printf("added state transition request [%d] [%s] \n", success, event.c_str()); - fflush(stdout); - } - else - { - printf("received wrong state transition request\n"); - // enable for debugging wrong state transition requests - // printf("expected [%s] but got [%s]\n", context->mPendingEventName.c_str(), event.c_str()); - // printf("pending state transition [%d]\n", context->mPendingStateTransition); - fflush(stdout); - } - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/LifecycleManagerImplementation.h b/LifecycleManager/LifecycleManagerImplementation.h deleted file mode 100755 index 0fc4ad4..0000000 --- a/LifecycleManager/LifecycleManagerImplementation.h +++ /dev/null @@ -1,161 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include "IEventHandler.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include "ApplicationContext.h" - -namespace WPEFramework -{ - namespace Plugin - { - class LifecycleManagerImplementation : public Exchange::ILifecycleManager - , public Exchange::ILifecycleManagerState - , public Exchange::IConfiguration - , public IEventHandler - { - public: - enum EventNames - { - LIFECYCLE_MANAGER_EVENT_APPSTATECHANGED, - LIFECYCLE_MANAGER_EVENT_RUNTIME, - LIFECYCLE_MANAGER_EVENT_WINDOW, - LIFECYCLE_MANAGER_EVENT_ONFAILURE - }; - - class EXTERNAL Job : public Core::IDispatch - { - protected: - Job(LifecycleManagerImplementation *lifeCycleManagerImplementation, EventNames event, JsonValue ¶ms) - : mLifecycleManagerImplementation(lifeCycleManagerImplementation) - , _event(event) - , _params(params) - { - if (mLifecycleManagerImplementation != nullptr) - { - mLifecycleManagerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() - { - if (mLifecycleManagerImplementation != nullptr) - { - mLifecycleManagerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(LifecycleManagerImplementation *lifeCycleManagerImplementation, EventNames event, JsonValue params) - { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(lifeCycleManagerImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(lifeCycleManagerImplementation, event, params))); -#endif - } - - virtual void Dispatch() - { - mLifecycleManagerImplementation->Dispatch(_event, _params); - } - private: - LifecycleManagerImplementation *mLifecycleManagerImplementation; - const EventNames _event; - const JsonValue _params; - }; - - LifecycleManagerImplementation (); - ~LifecycleManagerImplementation () override; - LifecycleManagerImplementation (const LifecycleManagerImplementation &) = delete; - LifecycleManagerImplementation & operator=(const LifecycleManagerImplementation &) = delete; - - BEGIN_INTERFACE_MAP(LifecycleManagerImplementation) - INTERFACE_ENTRY(Exchange::ILifecycleManager) - INTERFACE_ENTRY(Exchange::ILifecycleManagerState) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - /* ILifecycleManager methods */ - virtual Core::hresult Register(Exchange::ILifecycleManager::INotification *notification) override; - virtual Core::hresult Unregister(Exchange::ILifecycleManager::INotification *notification) override; - virtual Core::hresult GetLoadedApps(const bool verbose, string& apps) override; - virtual Core::hresult IsAppLoaded(const string& appId, bool& loaded) const override; - virtual Core::hresult SpawnApp(const string& appId, const string& launchIntent, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, const string& launchArgs, string& appInstanceId, string& errorReason, bool& success) override; - virtual Core::hresult SetTargetAppState(const string& appInstanceId, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, const string& launchIntent) override; - virtual Core::hresult UnloadApp(const string& appInstanceId, string& errorReason, bool& success) override; - virtual Core::hresult KillApp(const string& appInstanceId, string& errorReason, bool& success) override; - virtual Core::hresult SendIntentToActiveApp(const string& appInstanceId, const string& intent, string& errorReason, bool& success) override; - - /* ILifecycleManagerState methods */ - /** Register notification interface */ - virtual Core::hresult Register(Exchange::ILifecycleManagerState::INotification *notification) override; - /** Unregister notification interface */ - virtual Core::hresult Unregister(Exchange::ILifecycleManagerState::INotification *notification) override; - virtual Core::hresult AppReady(const string& appId) override; - virtual Core::hresult StateChangeComplete(const string& appId, const uint32_t stateChangedId, const bool success) override; - virtual Core::hresult CloseApp(const string& appId, const AppCloseReason closeReason) override; - - /* IConfiguration methods */ - uint32_t Configure(PluginHost::IShell* service) override; - - /* IEventHandler methods */ - virtual void onRuntimeManagerEvent(JsonObject& data) override; - virtual void onWindowManagerEvent(JsonObject& data) override; - virtual void onRippleEvent(string name, JsonObject& data) override; - virtual void onStateChangeEvent(JsonObject& data) override; - - private: /* members */ - mutable Core::CriticalSection mAdminLock; - std::list mLifecycleManagerNotification; - std::list mLifecycleManagerStateNotification; - std::list mLoadedApplications; - PluginHost::IShell* mService; - private: /* internal methods */ - bool initialize(PluginHost::IShell* service); - void terminate(); - void dispatchEvent(EventNames, const JsonValue ¶ms); - void Dispatch(EventNames event, const JsonValue params); - void handleRuntimeManagerEvent(const JsonObject &data); - void notifyOnFailure(const string& appInstanceId, const string& errorCode); - void handleStateChangeEvent(const JsonObject &data); - void handleWindowManagerEvent(const JsonObject &data); - ApplicationContext* getContext(const string& appInstanceId, const string& appId) const; - void addStateTransitionRequest(ApplicationContext* context, std::string event); - - friend class Job; - -#ifdef UNIT_TEST - friend class LifecycleManagerImplementationTest; -#endif - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/LifecycleManagerTelemetryReporting.cpp b/LifecycleManager/LifecycleManagerTelemetryReporting.cpp deleted file mode 100755 index 6ede213..0000000 --- a/LifecycleManager/LifecycleManagerTelemetryReporting.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "LifecycleManagerTelemetryReporting.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework -{ -namespace Plugin -{ - LifecycleManagerTelemetryReporting::LifecycleManagerTelemetryReporting(): mTelemetryMetricsObject(nullptr), mCurrentservice(nullptr) - { - } - - LifecycleManagerTelemetryReporting::~LifecycleManagerTelemetryReporting() - { - if(mTelemetryMetricsObject ) - { - mTelemetryMetricsObject ->Release(); - mTelemetryMetricsObject = nullptr; - mCurrentservice = nullptr; - } - } - - LifecycleManagerTelemetryReporting& LifecycleManagerTelemetryReporting::getInstance() - { - LOGINFO("Get LifecycleManagerTelemetryReporting Instance"); - static LifecycleManagerTelemetryReporting instance; - return instance; - } - - void LifecycleManagerTelemetryReporting::initialize(PluginHost::IShell* service) - { - ASSERT(nullptr != service); - mAdminLock.Lock(); - mCurrentservice = service; - mAdminLock.Unlock(); - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - time_t LifecycleManagerTelemetryReporting::getCurrentTimestamp() - { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((time_t)(ts.tv_sec * 1000) + ((time_t)ts.tv_nsec/1000000)); - } - -/* -* Creates TelemetryMetrics plugin object to access interface methods -*/ - Core::hresult LifecycleManagerTelemetryReporting::createTelemetryMetricsPluginObject() - { - Core::hresult status = Core::ERROR_GENERAL; - - mAdminLock.Lock(); - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null \n"); - } - else if (nullptr == (mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"))) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - else - { - status = Core::ERROR_NONE; - LOGINFO("created TelemetryMetrics Object"); - } - mAdminLock.Unlock(); - return status; - } - - void LifecycleManagerTelemetryReporting::reportTelemetryDataOnStateChange(ApplicationContext* context, const JsonObject &data) - { - string appId = ""; - RequestType requestType = REQUEST_TYPE_NONE; - time_t requestTime = 0; - time_t currentTime = 0; - Exchange::ILifecycleManager::LifecycleState targetLifecycleState; - Exchange::ILifecycleManager::LifecycleState newLifecycleState; - JsonObject jsonParam; - std::string telemetryMetrics = ""; - std::string markerName = ""; - bool shouldPublish = false; - - if(nullptr == mTelemetryMetricsObject) /*mTelemetryMetricsObject is null retry to create*/ - { - if(Core::ERROR_NONE != createTelemetryMetricsPluginObject()) - { - LOGERR("Failed to create TelemetryMetricsObject\n"); - } - } - - if (nullptr == context) - { - LOGERR("context is nullptr"); - } - else if (nullptr == mTelemetryMetricsObject) - { - LOGERR("mTelemetryMetricsObject is not valid"); - } - else if (!data.HasLabel("appId") || (appId = data["appId"].String()).empty()) - { - LOGERR("appId not present or empty"); - } - else - { - requestType = context->getRequestType(); - requestTime = context->getRequestTime(); - currentTime = getCurrentTimestamp(); - targetLifecycleState = context->getTargetLifecycleState(); - newLifecycleState = static_cast(data["newLifecycleState"].Number()); - LOGINFO("Received state change for appId %s newLifecycleState %d requestType %d", appId.c_str(), newLifecycleState, requestType); - - switch(requestType) - { - case REQUEST_TYPE_LAUNCH: - if (((Exchange::ILifecycleManager::LifecycleState::ACTIVE == newLifecycleState) && (Exchange::ILifecycleManager::LifecycleState::ACTIVE == targetLifecycleState)) || - ((Exchange::ILifecycleManager::LifecycleState::PAUSED == newLifecycleState) && (Exchange::ILifecycleManager::LifecycleState::PAUSED == targetLifecycleState))) - { - /*Telemetry reporting - launch case*/ - jsonParam["lifecycleManagerSpawnTime"] = (int)(currentTime - requestTime); - jsonParam.ToString(telemetryMetrics); - markerName = TELEMETRY_MARKER_LAUNCH_TIME; - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - } - break; - case REQUEST_TYPE_TERMINATE: - if(Exchange::ILifecycleManager::LifecycleState::UNLOADED == newLifecycleState) - { - /*Telemetry reporting - close case*/ - jsonParam["lifecycleManagerSetTargetStateTime"] = (int)(currentTime - requestTime); - jsonParam.ToString(telemetryMetrics); - markerName = TELEMETRY_MARKER_CLOSE_TIME; - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - } - else if(Exchange::ILifecycleManager::LifecycleState::SUSPENDED == newLifecycleState) - { - /*Telemetry reporting - wake case, wake is called during app terminate*/ - markerName = TELEMETRY_MARKER_WAKE_TIME; - shouldPublish = true; - } - break; - case REQUEST_TYPE_SUSPEND: - /*Telemetry reporting - suspend case*/ - if(Exchange::ILifecycleManager::LifecycleState::SUSPENDED == newLifecycleState) - { - markerName = TELEMETRY_MARKER_SUSPEND_TIME; - shouldPublish = true; - } - break; - case REQUEST_TYPE_RESUME: - /*Telemetry reporting - resume case*/ - if(Exchange::ILifecycleManager::LifecycleState::ACTIVE == newLifecycleState) - { - markerName = TELEMETRY_MARKER_RESUME_TIME; - shouldPublish = true; - } - break; - case REQUEST_TYPE_HIBERNATE: - /*Telemetry reporting - hibernate case*/ - if(Exchange::ILifecycleManager::LifecycleState::HIBERNATED == newLifecycleState) - { - markerName = TELEMETRY_MARKER_HIBERNATE_TIME; - shouldPublish = true; - } - break; - default: - LOGERR("requestType is invalid"); - break; - } - - if (!markerName.empty() && shouldPublish) - { - jsonParam["appId"] = appId; - jsonParam["appInstanceId"] = context->getAppInstanceId(); - jsonParam["lifecycleManagerSetTargetStateTime"] = (int)(currentTime - requestTime); - jsonParam.ToString(telemetryMetrics); - if(!telemetryMetrics.empty()) - { - mTelemetryMetricsObject->Record(appId, telemetryMetrics, markerName); - mTelemetryMetricsObject->Publish(appId, markerName); - } - } - } - } - -} /* namespace Plugin */ -} /* namespace WPEFramework */ - diff --git a/LifecycleManager/LifecycleManagerTelemetryReporting.h b/LifecycleManager/LifecycleManagerTelemetryReporting.h deleted file mode 100755 index 45110c0..0000000 --- a/LifecycleManager/LifecycleManagerTelemetryReporting.h +++ /dev/null @@ -1,60 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "ApplicationContext.h" -#include - -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#define TELEMETRY_MARKER_CLOSE_TIME "AppCloseTime_split" -#define TELEMETRY_MARKER_SUSPEND_TIME "SuspendTime_split" -#define TELEMETRY_MARKER_RESUME_TIME "ResumeTime_split" -#define TELEMETRY_MARKER_HIBERNATE_TIME "HibernateTime_split" -#define TELEMETRY_MARKER_WAKE_TIME "WakeTime_split" - -namespace WPEFramework -{ -namespace Plugin -{ - -class LifecycleManagerTelemetryReporting -{ - public /*methods*/: - LifecycleManagerTelemetryReporting(const LifecycleManagerTelemetryReporting&) = delete; - LifecycleManagerTelemetryReporting& operator=(const LifecycleManagerTelemetryReporting&) = delete; - static LifecycleManagerTelemetryReporting& getInstance(); - void reportTelemetryDataOnStateChange(ApplicationContext* context, const JsonObject &data); - time_t getCurrentTimestamp(); - void initialize(PluginHost::IShell* service); - - private /*methods*/: - LifecycleManagerTelemetryReporting(); - ~LifecycleManagerTelemetryReporting(); - Core::hresult createTelemetryMetricsPluginObject(); - - private /*members*/: - mutable Core::CriticalSection mAdminLock; - Exchange::ITelemetryMetrics* mTelemetryMetricsObject; - PluginHost::IShell* mCurrentservice; -}; - -} /* namespace Plugin */ -} /* namespace WPEFramework */ - diff --git a/LifecycleManager/Module.cpp b/LifecycleManager/Module.cpp deleted file mode 100644 index cd6d4d1..0000000 --- a/LifecycleManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/LifecycleManager/Module.h b/LifecycleManager/Module.h deleted file mode 100755 index 9f12643..0000000 --- a/LifecycleManager/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_LifecycleManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/LifecycleManager/README.md b/LifecycleManager/README.md deleted file mode 100755 index 26dae1d..0000000 --- a/LifecycleManager/README.md +++ /dev/null @@ -1,18 +0,0 @@ ------------------ -# LifecycleManager - -## Versions -`org.rdk.LifecycleManager.1` - -## Methods: -``` -``` - -## Responses -``` -``` - -## Events -``` -none -``` diff --git a/LifecycleManager/RequestHandler.cpp b/LifecycleManager/RequestHandler.cpp deleted file mode 100644 index 43470e3..0000000 --- a/LifecycleManager/RequestHandler.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "RequestHandler.h" -#include "StateTransitionHandler.h" -#include -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - RequestHandler* RequestHandler::mInstance = nullptr; - - RequestHandler* RequestHandler::getInstance() - { - if (nullptr == mInstance) - { - mInstance = new RequestHandler(); - } - return mInstance; - } - - RequestHandler::RequestHandler(): mRuntimeManagerHandler(nullptr), mWindowManagerHandler(nullptr), mEventHandler(nullptr) - { - } - - RequestHandler::~RequestHandler() - { - } - - bool RequestHandler::initialize(PluginHost::IShell* service, IEventHandler* eventHandler) - { - bool ret = false; - mEventHandler = eventHandler; - mRuntimeManagerHandler = new RuntimeManagerHandler(); - ret = mRuntimeManagerHandler->initialize(service, eventHandler); - if (!ret) - { - printf("unable to initialize with runtimemanager \n"); - fflush(stdout); - return ret; - } - mWindowManagerHandler = new WindowManagerHandler(); - ret = mWindowManagerHandler->initialize(service, eventHandler); - if (!ret) - { - printf("unable to initialize with windowmanager \n"); - fflush(stdout); - return ret; - } - StateTransitionHandler::getInstance()->initialize(); - return ret; - } - - void RequestHandler::terminate() - { - StateTransitionHandler::getInstance()->terminate(); - if (mWindowManagerHandler) - { - mWindowManagerHandler->terminate(); - delete mWindowManagerHandler; - mWindowManagerHandler = nullptr; - } - - if (mRuntimeManagerHandler) - { - mRuntimeManagerHandler->deinitialize(); - delete mRuntimeManagerHandler; - mRuntimeManagerHandler = nullptr; - } - } - - bool RequestHandler::launch(ApplicationContext* context, const string& launchIntent, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, string& errorReason) - { - bool success = updateState(context, targetLifecycleState, errorReason); - return success; - } - - bool RequestHandler::terminate(ApplicationContext* context, bool force, string& errorReason) - { - bool success = false; - success = updateState(context, Exchange::ILifecycleManager::LifecycleState::TERMINATING, errorReason); - return success; - } - - bool RequestHandler::sendIntent(ApplicationContext* context, const string& intent, string& errorReason) - { - context->setMostRecentIntent(intent); - return true; - } - - bool RequestHandler::updateState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState state, string& errorReason) - { - StateTransitionRequest request(context, state); - StateTransitionHandler::getInstance()->addRequest(request); - return true; - } - - RuntimeManagerHandler* RequestHandler::getRuntimeManagerHandler() - { - return mRuntimeManagerHandler; - } - - WindowManagerHandler* RequestHandler::getWindowManagerHandler() - { - return mWindowManagerHandler; - } - - IEventHandler* RequestHandler::getEventHandler() - { - return mEventHandler; - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/RequestHandler.h b/LifecycleManager/RequestHandler.h deleted file mode 100644 index 99ec8de..0000000 --- a/LifecycleManager/RequestHandler.h +++ /dev/null @@ -1,59 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "ApplicationContext.h" -#include "RuntimeManagerHandler.h" -#include "WindowManagerHandler.h" -#include "IEventHandler.h" - -namespace WPEFramework -{ - namespace Plugin - { - class RequestHandler - { - public: - RequestHandler(const RequestHandler& obj) = delete; - static RequestHandler* getInstance(); - ~RequestHandler (); - bool initialize(PluginHost::IShell* service, IEventHandler* eventHandler); - void terminate(); - - bool launch(ApplicationContext* context, const string& launchIntent, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, string& errorReason); - bool terminate(ApplicationContext* context, bool force, string& errorReason); - bool sendIntent(ApplicationContext* context, const string& intent, string& errorReason); - bool updateState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState targetLifecycleState, string& errorReason); - RuntimeManagerHandler* getRuntimeManagerHandler(); - WindowManagerHandler* getWindowManagerHandler(); - IEventHandler* getEventHandler(); - - private: /* members */ - RequestHandler(); - - static RequestHandler* mInstance; - - // different component handlers - RuntimeManagerHandler* mRuntimeManagerHandler; - WindowManagerHandler* mWindowManagerHandler; - IEventHandler* mEventHandler; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/RuntimeManagerHandler.cpp b/LifecycleManager/RuntimeManagerHandler.cpp deleted file mode 100644 index f9c19d4..0000000 --- a/LifecycleManager/RuntimeManagerHandler.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "RuntimeManagerHandler.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - -#define FIREBOLT_ENDPOINT_APPACCESS_PORT 3473 - -RuntimeManagerHandler::RuntimeManagerHandler() -: mRuntimeManager(nullptr), mRuntimeManagerNotification(*this), mFireboltAccessPort(FIREBOLT_ENDPOINT_APPACCESS_PORT), mEventHandler(nullptr) -{ - LOGINFO("Create RuntimeManagerHandler Instance"); -} - -RuntimeManagerHandler::~RuntimeManagerHandler() -{ - LOGINFO("Delete RuntimeManagerHandler Instance"); -} - -bool RuntimeManagerHandler::initialize(PluginHost::IShell* service, IEventHandler* eventHandler) -{ - bool ret = false; - mEventHandler = eventHandler; - mRuntimeManager = service->QueryInterfaceByCallsign("org.rdk.RuntimeManager"); - if (mRuntimeManager != nullptr) - { - ret = true; - Core::hresult registerResult = mRuntimeManager->Register(&mRuntimeManagerNotification); - if (Core::ERROR_NONE != registerResult) - { - LOGINFO("Unable to register with runtimemanager [%d] \n", registerResult); - } - } - else - { - LOGERR("runtimemanager is null \n"); - } - return ret; -} - -void RuntimeManagerHandler::deinitialize() -{ - Core::hresult unregisterResult = mRuntimeManager->Unregister(&mRuntimeManagerNotification); - if (Core::ERROR_NONE != unregisterResult) - { - LOGINFO("Unable to unregister from runtimemanager [%d] \n", unregisterResult); - } - uint32_t result = mRuntimeManager->Release(); - LOGINFO("Terminated runtime manager hanlder [%d] \n", result); - mRuntimeManager = nullptr; -} - -bool RuntimeManagerHandler::getRuntimeStats(const string& appInstanceId, string& info) -{ - Core::hresult result = mRuntimeManager->GetInfo(appInstanceId, info); - if (Core::ERROR_NONE != result) - { - LOGINFO("unable to get information about application"); - return false; - } - return true; -} - -bool RuntimeManagerHandler::run(const string& appId, const string& appInstanceId, const string& launchArgs, Exchange::ILifecycleManager::LifecycleState targetState, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, string& errorReason) -{ - JsonArray debugSettingsArray, pathsArray, portsArray; - // read data from parameters - // QUESTION HOW TO GET OTHER PARAMS ports, paths, debugsettings? - // convert launchArgs to meaningful environment variables when launching a container - - // FOR Q1 - // -- debugSettings - [] //for vbn builds - // -- paths - paths to set in container - path for XDG_RUNTIME_DIR - - runtimeConfigObject.dialId = appId; - - uint32_t userId = 0, groupId = 0; - std::list debugSettingsList, pathsList; - std::list portsList; - JsonArray envNewArray; - - portsList.push_back(mFireboltAccessPort); - - std::stringstream ss; - ss << "FIREBOLT_ENDPOINT=http://127.0.0.1:" << mFireboltAccessPort << "?session=" << appInstanceId; - string fireboltEndPoint(ss.str()); - envNewArray.Add(fireboltEndPoint); - - std::stringstream targetAppStateEnvironmentString; - targetAppStateEnvironmentString << "TARGET_STATE=" << (uint32_t)targetState; - string targetAppState(targetAppStateEnvironmentString.str()); - envNewArray.Add(targetAppState); - - JsonArray envInputArray, envResultArray; - envInputArray.FromString(runtimeConfigObject.envVariables); - for (unsigned int i = 0; i < envInputArray.Length(); ++i) - { - envResultArray.Add(envInputArray[i].String()); - } - for (unsigned int i = 0; i < envNewArray.Length(); ++i) - { - envResultArray.Add(envNewArray[i].String()); - } - envResultArray.ToString(runtimeConfigObject.envVariables); - - // prepare arguments to pass - RPC::IStringIterator* debugSettingsIterator{}; - RPC::IStringIterator* pathsIterator{}; - RPC::IValueIterator* portsIterator{}; - - debugSettingsIterator = Core::Service::Create(debugSettingsList); - pathsIterator = Core::Service::Create(pathsList); - portsIterator = Core::Service::Create(portsList); - - Core::hresult result = mRuntimeManager->Run(appId, appInstanceId, userId, groupId, portsIterator, pathsIterator, debugSettingsIterator, runtimeConfigObject); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to start running application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::kill(const string& appInstanceId, string& errorReason) -{ - Core::hresult result = mRuntimeManager->Kill(appInstanceId); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to kill application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::terminate(const string& appInstanceId, string& errorReason) -{ - Core::hresult result = mRuntimeManager->Terminate(appInstanceId); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to terminate application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::suspend(const string& appInstanceId, string& errorReason) -{ - Core::hresult result = mRuntimeManager->Suspend(appInstanceId); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to suspend application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::resume(const string& appInstanceId, string& errorReason) -{ - Core::hresult result = mRuntimeManager->Resume(appInstanceId); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to resume application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::hibernate(const string& appInstanceId, string& errorReason) -{ - Core::hresult result = mRuntimeManager->Hibernate(appInstanceId); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to hibernate application"; - return false; - } - return true; -} - -bool RuntimeManagerHandler::wake(const string& appInstanceId, Exchange::ILifecycleManager::LifecycleState state, string& errorReason) -{ - Exchange::IRuntimeManager::RuntimeState runtimeState = Exchange::IRuntimeManager::RuntimeState::RUNTIME_STATE_UNKNOWN; - if (state == Exchange::ILifecycleManager::LifecycleState::SUSPENDED) - { - runtimeState = Exchange::IRuntimeManager::RuntimeState::RUNTIME_STATE_SUSPENDED; - } - else if ((state == Exchange::ILifecycleManager::LifecycleState::PAUSED) || (state == Exchange::ILifecycleManager::LifecycleState::ACTIVE)) - { - runtimeState = Exchange::IRuntimeManager::RuntimeState::RUNTIME_STATE_RUNNING; - } - Core::hresult result = mRuntimeManager->Wake(appInstanceId, runtimeState); - if (Core::ERROR_NONE != result) - { - errorReason = "unable to wakeup application"; - return false; - } - return true; -} - -void RuntimeManagerHandler::RuntimeManagerNotification::OnStarted(const string& appInstanceId) -{ - JsonObject eventData; - eventData["appInstanceId"] = appInstanceId; - eventData["name"] = "onStarted"; - _parent.onEvent(eventData); -} - -void RuntimeManagerHandler::RuntimeManagerNotification::OnTerminated(const string& appInstanceId) -{ - JsonObject eventData; - eventData["appInstanceId"] = appInstanceId; - eventData["name"] = "onTerminated"; - _parent.onEvent(eventData); -} - -void RuntimeManagerHandler::RuntimeManagerNotification::OnFailure(const string& appInstanceId, const string& error) -{ - JsonObject eventData; - eventData["appInstanceId"] = appInstanceId; - eventData["name"] = "onFailure"; - eventData["errorCode"] = error; - _parent.onEvent(eventData); -} - -void RuntimeManagerHandler::RuntimeManagerNotification::OnStateChanged(const string& appInstanceId, Exchange::IRuntimeManager::RuntimeState state) -{ - JsonObject eventData; - eventData["appInstanceId"] = appInstanceId; - eventData["state"] = (uint32_t)state; - eventData["name"] = "onStateChanged"; - _parent.onEvent(eventData); -} - -void RuntimeManagerHandler::onEvent(JsonObject& data) -{ - if (mEventHandler) - { - mEventHandler->onRuntimeManagerEvent(data); - } -} - -} // namespace Plugin -} // namespace WPEFramework diff --git a/LifecycleManager/RuntimeManagerHandler.h b/LifecycleManager/RuntimeManagerHandler.h deleted file mode 100644 index a6d6c25..0000000 --- a/LifecycleManager/RuntimeManagerHandler.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include -#include -#include -#include "IEventHandler.h" -#include "ApplicationContext.h" - -namespace WPEFramework { -namespace Plugin { - class RuntimeManagerHandler - { - class RuntimeManagerNotification : public Exchange::IRuntimeManager::INotification - { - private: - RuntimeManagerNotification(const RuntimeManagerNotification&) = delete; - RuntimeManagerNotification& operator=(const RuntimeManagerNotification&) = delete; - - public: - explicit RuntimeManagerNotification(RuntimeManagerHandler& parent) - : _parent(parent) - { - } - - virtual void OnStarted(const string& appInstanceId) override; - virtual void OnTerminated(const string& appInstanceId) override; - virtual void OnFailure(const string& appInstanceId, const string& error) override; - virtual void OnStateChanged(const string& appInstanceId, Exchange::IRuntimeManager::RuntimeState state) override; - - ~RuntimeManagerNotification() override = default; - BEGIN_INTERFACE_MAP(RuntimeManagerNotification) - INTERFACE_ENTRY(Exchange::IRuntimeManager::INotification) - END_INTERFACE_MAP - - private: - RuntimeManagerHandler& _parent; - }; - - public: - RuntimeManagerHandler(); - ~RuntimeManagerHandler(); - - // We do not allow this plugin to be copied !! - RuntimeManagerHandler(const RuntimeManagerHandler&) = delete; - RuntimeManagerHandler& operator=(const RuntimeManagerHandler&) = delete; - - public: - bool initialize(PluginHost::IShell* service, IEventHandler* eventHandler); - void deinitialize(); - bool run(const string& appId, const string& appInstanceId, const string& launchArgs, Exchange::ILifecycleManager::LifecycleState targetState, WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, string& errorReason); - bool kill(const string& appInstanceId, string& errorReason); - bool terminate(const string& appInstanceId, string& errorReason); - bool suspend(const string& appInstanceId, string& errorReason); - bool resume(const string& appInstanceId, string& errorReason); - bool hibernate(const string& appInstanceId, string& errorReason); - bool wake(const string& appInstanceId, Exchange::ILifecycleManager::LifecycleState state, string& errorReason); - bool getRuntimeStats(const string& appInstanceId, string& info); - void onEvent(JsonObject& data); - - private: - Exchange::IRuntimeManager* mRuntimeManager; - Core::Sink mRuntimeManagerNotification; - uint32_t mFireboltAccessPort; - IEventHandler* mEventHandler; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/LifecycleManager/State.cpp b/LifecycleManager/State.cpp deleted file mode 100644 index bf65190..0000000 --- a/LifecycleManager/State.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "StateHandler.h" -#include -#include "RuntimeManagerHandler.h" -#include "RequestHandler.h" -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - bool UnloadedState::handle(string& errorReason) - { - return true; - } - - bool LoadingState::handle(string& errorReason) - { - ApplicationContext* context = getContext(); - - boost::uuids::uuid tag = boost::uuids::random_generator()(); - std::string generatedInstanceId = boost::uuids::to_string(tag); - context->setAppInstanceId(generatedInstanceId); - sem_post(&context->mReachedLoadingStateSemaphore); - return true; - } - - bool InitializingState::handle(string& errorReason) - { - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - bool ret = false; - if (nullptr != runtimeManagerHandler) - { - ApplicationContext* context = getContext(); - ApplicationLaunchParams& launchParams = context->getApplicationLaunchParams(); - ret = runtimeManagerHandler->run(context->getAppId(), context->getAppInstanceId(), launchParams.mLaunchArgs, launchParams.mTargetState, launchParams.mRuntimeConfigObject, errorReason); - ret = true; - context->mPendingEventName = "onAppRunning"; - context->mPendingStateTransition = true; - } - return ret; - } - - bool PausedState::handle(string& errorReason) - { - bool ret = false; - ApplicationContext* context = getContext(); - if (Exchange::ILifecycleManager::LifecycleState::INITIALIZING == context->getCurrentLifecycleState()) - { - //TODO : Remove wait for now - //context->mPendingEventName = ""; - //context->mPendingStateTransition = true; - //sem_wait(&context->mAppReadySemaphore); - ret = true; - } - else if (Exchange::ILifecycleManager::LifecycleState::SUSPENDED == context->getCurrentLifecycleState()) - { - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - //ret = runtimeManagerHandler->resume(context->getAppInstanceId(), errorReason); - WindowManagerHandler *windowManagerHandler = RequestHandler::getInstance()->getWindowManagerHandler(); - if (nullptr != windowManagerHandler) - { - ApplicationContext *context = getContext(); - Core::hresult retValue = windowManagerHandler->enableDisplayRender(context->getAppInstanceId(), true); - printf("enabled display in window manager [%d] \n", retValue); - fflush(stdout); - } - ret = true; - //TODO: Error cases - } - } - else if (Exchange::ILifecycleManager::LifecycleState::ACTIVE == context->getCurrentLifecycleState()) - { - ret = true; - } - return ret; - } - - bool ActiveState::handle(string& errorReason) - { - WindowManagerHandler* windowManagerHandler = RequestHandler::getInstance()->getWindowManagerHandler(); - if (nullptr != windowManagerHandler) - { - ApplicationContext* context = getContext(); - bool isRenderReady = false; - Core::hresult ret = windowManagerHandler->renderReady(context->getAppInstanceId(), isRenderReady); - if (Core::ERROR_NONE == ret) - { - if (isRenderReady) - { - return true; - } - else - { - context->mPendingEventName = "onFirstFrame"; - context->mPendingStateTransition = true; - } - } - else - { - return false; - } - } - return true; - } - - bool SuspendedState::handle(string& errorReason) - { - bool ret = false; - //TODO : Remove wait for now - //ApplicationContext* context = getContext(); - //sem_wait(&context->mAppReadySemaphore); - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - ApplicationContext* context = getContext(); - if (Exchange::ILifecycleManager::LifecycleState::HIBERNATED == context->getCurrentLifecycleState()) - { - ret = runtimeManagerHandler->wake(context->getAppInstanceId(), Exchange::ILifecycleManager::LifecycleState::SUSPENDED, errorReason); - } - else - { - //ret = runtimeManagerHandler->suspend(context->getAppInstanceId(), errorReason); - WindowManagerHandler *windowManagerHandler = RequestHandler::getInstance()->getWindowManagerHandler(); - if (nullptr != windowManagerHandler) - { - ApplicationContext *context = getContext(); - Core::hresult retValue = windowManagerHandler->enableDisplayRender(context->getAppInstanceId(), false); - printf("disabled display in window manager [%d] \n", retValue); - fflush(stdout); - ret = true; - } - //TODO: Handle error cases - } - } - return ret; - } - - bool HibernatedState::handle(string& errorReason) - { - bool ret = false; - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - ApplicationContext* context = getContext(); - ret = runtimeManagerHandler->hibernate(context->getAppInstanceId(), errorReason); - } - return ret; - } -/* - bool WakeRequestedState::handle(string& errorReason) - { - bool ret = false; - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - ApplicationContext* context = getContext(); - ret = runtimeManagerHandler->wake(context->getAppInstanceId(), context->getTargetLifecycleState(), errorReason); - } - return ret; - } -*/ - - bool TerminatingState::handle(string& errorReason) - { - bool success = false; - RuntimeManagerHandler* runtimeManagerHandler = RequestHandler::getInstance()->getRuntimeManagerHandler(); - if (nullptr != runtimeManagerHandler) - { - ApplicationContext* context = getContext(); - ApplicationKillParams& killParams = context->getApplicationKillParams(); - if (killParams.mForce) - { - success = runtimeManagerHandler->kill(context->getAppInstanceId(), errorReason); - } - else - { - success = runtimeManagerHandler->terminate(context->getAppInstanceId(), errorReason); - } - if(success) - { - context->mPendingEventName = "onAppTerminating"; - context->mPendingStateTransition = true; - } - } - return success; - } - } -} /* namespace WPEFramework */ diff --git a/LifecycleManager/State.h b/LifecycleManager/State.h deleted file mode 100644 index 44cd956..0000000 --- a/LifecycleManager/State.h +++ /dev/null @@ -1,121 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -//class ApplicationContext; - -namespace WPEFramework -{ - namespace Plugin - { - class State - { - public: - State(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState state): mState(state), mContext(context) {} - virtual ~State() {} - - virtual bool handle(string& errorReason) - { - return true; - } - - virtual Exchange::ILifecycleManager::LifecycleState getValue() - { - return mState; - } - - virtual ApplicationContext* getContext() - { - return mContext; - } - - private: /* members */ - Exchange::ILifecycleManager::LifecycleState mState; - ApplicationContext* mContext; - }; - - class UnloadedState : public State - { - public: - UnloadedState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::UNLOADED) {} - ~UnloadedState() {} - bool handle(string& errorReason); - }; - - class LoadingState : public State - { - public: - LoadingState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::LOADING) {} - ~LoadingState() {} - bool handle(string& errorReason); - }; - - class InitializingState : public State - { - public: - InitializingState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::INITIALIZING) {} - ~InitializingState() {} - bool handle(string& errorReason); - }; - - class PausedState : public State - { - public: - PausedState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::PAUSED) {} - ~PausedState() {} - bool handle(string& errorReason); - }; - - class ActiveState : public State - { - public: - ActiveState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::ACTIVE) {} - ~ActiveState() {} - bool handle(string& errorReason); - }; - - class SuspendedState : public State - { - public: - SuspendedState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::SUSPENDED) {} - ~SuspendedState() {} - bool handle(string& errorReason); - }; - - class HibernatedState : public State - { - public: - HibernatedState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::HIBERNATED) {} - ~HibernatedState() {} - bool handle(string& errorReason); - }; - - class TerminatingState : public State - { - public: - TerminatingState(ApplicationContext* context): State(context, Exchange::ILifecycleManager::LifecycleState::TERMINATING) {} - ~TerminatingState() {} - bool handle(string& errorReason); - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/StateHandler.cpp b/LifecycleManager/StateHandler.cpp deleted file mode 100644 index 23eba6b..0000000 --- a/LifecycleManager/StateHandler.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "StateHandler.h" -#include -#include -#include -#include "IEventHandler.h" -#include "RequestHandler.h" - -namespace WPEFramework -{ - namespace Plugin - { - typedef Exchange::ILifecycleManager::LifecycleState Lifecycle; - std::map> StateHandler::mPossibleStateTransitions = std::map>(); - std::map StateHandler::mStateStrings = std::map(); - uint32_t StateHandler::sStateChangeCount = 0; - - bool StateHandler::updateState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifeCycleState, string& errorReason) - { - State* currentState = (State*) context->getState(); - bool result = false; - if ((nullptr != currentState) && (currentState->getValue() == lifeCycleState)) - { - return true; - } - State* newState = createState(context, lifeCycleState); - if (nullptr != newState) - { - //context->setState(nullptr); - result = newState->handle(errorReason); - if (result) - { - context->setState(newState); - delete currentState; - } - } - return result; - } - - State* StateHandler::createState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifeCycleState) - { - State* state = nullptr; - switch (lifeCycleState) - { - case Exchange::ILifecycleManager::LifecycleState::UNLOADED: - state = new UnloadedState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::LOADING: - state = new LoadingState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::INITIALIZING: - state = new InitializingState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::PAUSED: - state = new PausedState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::ACTIVE: - state = new ActiveState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::SUSPENDED: - state = new SuspendedState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::HIBERNATED: - state = new HibernatedState(context); - break; - case Exchange::ILifecycleManager::LifecycleState::TERMINATING: - state = new TerminatingState(context); - break; - default: - state = nullptr; - } - return state; - } - - bool StateHandler::isValidTransition(Exchange::ILifecycleManager::LifecycleState start, Exchange::ILifecycleManager::LifecycleState target, std::map& pathSequence, std::vector& foundPath) - { - bool pathPresent = false; - if (start == target) - { - return true; - } - pathSequence[target] = true; - std::map>::iterator transitionIter = mPossibleStateTransitions.find(target); - if (transitionIter == mPossibleStateTransitions.end()) - { - return false; - } - std::list& transitionList = transitionIter->second; - for (auto iter = transitionList.begin(); iter != transitionList.end(); ++iter) - { - if (pathSequence.find(*iter) != pathSequence.end()) - { - continue; - } - - pathPresent = isValidTransition(start, *iter, pathSequence, foundPath); - if (pathPresent) - { - foundPath.push_back(*iter); - break; - } - } - return pathPresent; - } - - void StateHandler::initialize() - { - mPossibleStateTransitions[Lifecycle::UNLOADED] = std::list(); - mPossibleStateTransitions[Lifecycle::LOADING] = std::list(1, Lifecycle::UNLOADED); - mPossibleStateTransitions[Lifecycle::INITIALIZING] = std::list(1, Lifecycle::LOADING); - - mPossibleStateTransitions[Lifecycle::PAUSED] = std::list(); - std::list& pausedStatePre = mPossibleStateTransitions[Lifecycle::PAUSED]; - pausedStatePre.push_back(Lifecycle::INITIALIZING); - pausedStatePre.push_back(Lifecycle::ACTIVE); - pausedStatePre.push_back(Lifecycle::SUSPENDED); - - mPossibleStateTransitions[Lifecycle::ACTIVE] = std::list(); - std::list& activeStatePre = mPossibleStateTransitions[Lifecycle::ACTIVE]; - activeStatePre.push_back(Lifecycle::PAUSED); - - mPossibleStateTransitions[Lifecycle::SUSPENDED] = std::list(); - std::list& suspendedStatePre = mPossibleStateTransitions[Lifecycle::SUSPENDED]; - suspendedStatePre.push_back(Lifecycle::INITIALIZING); - suspendedStatePre.push_back(Lifecycle::PAUSED); - suspendedStatePre.push_back(Lifecycle::HIBERNATED); - - mPossibleStateTransitions[Lifecycle::HIBERNATED] = std::list(1, Lifecycle::SUSPENDED); - - mPossibleStateTransitions[Lifecycle::TERMINATING] = std::list(); - std::list& terminatingStatePre = mPossibleStateTransitions[Lifecycle::TERMINATING]; - terminatingStatePre.push_back(Lifecycle::PAUSED); - terminatingStatePre.push_back(Lifecycle::SUSPENDED); - - //state strings - mStateStrings[Lifecycle::UNLOADED] = "Unloaded"; - mStateStrings[Lifecycle::LOADING] = "Loading"; - mStateStrings[Lifecycle::INITIALIZING] = "Initializing"; - mStateStrings[Lifecycle::PAUSED] = "Paused"; - mStateStrings[Lifecycle::ACTIVE] = "Active"; - mStateStrings[Lifecycle::SUSPENDED] = "Suspended"; - mStateStrings[Lifecycle::HIBERNATED] = "Hibernated"; - mStateStrings[Lifecycle::TERMINATING] = "Terminating"; - } - - bool StateHandler::changeState(StateTransitionRequest& request, string& errorReason) - { - Exchange::ILifecycleManager::LifecycleState lifecycleState = request.mTargetState; - ApplicationContext* context = request.mContext; - - if (context == nullptr) - { - errorReason = "ApplicationContext is null"; - return false; - } - Exchange::ILifecycleManager::LifecycleState currentLifecycleState = context->getCurrentLifecycleState(); - - if ((context->mPendingStateTransition) && (Exchange::ILifecycleManager::LifecycleState::TERMINATING != currentLifecycleState)) - { - sendEvent(context, context->mPendingOldState, currentLifecycleState, errorReason); - } - - if ((false == context->mPendingStateTransition) && (currentLifecycleState == lifecycleState)) - { - return true; - } - - std::vector statePath; - bool result = getStatePath(context, lifecycleState, statePath, errorReason); - if (false == result) - { - printf("Unable to get sequence for target state \n"); - fflush(stdout); - return false; - } - - bool isStateTerminating = false; - size_t lastStateIndex = static_cast(-1); - context->mPendingStateTransition = false; - - // start from next state - for (size_t stateIndex=1; stateIndexgetState())->getValue(); - isStateTerminating = (Exchange::ILifecycleManager::LifecycleState::TERMINATING == statePath[stateIndex]); - if (!isStateTerminating) - { - result = updateState(context, statePath[stateIndex], errorReason); - if(result) - { - printf("StateHandler::changeState: Success %s -> %s\n", mStateStrings[oldLifecycleState].c_str(), mStateStrings[statePath[stateIndex]].c_str()); - } - else - { - printf("StateHandler::changeState: Failed to change state from %s to %s\n", mStateStrings[oldLifecycleState].c_str(), mStateStrings[statePath[stateIndex]].c_str()); - break; - } - if (true == context->mPendingStateTransition) - { - context->mPendingOldState = oldLifecycleState; - lastStateIndex = stateIndex; - break; - } - } - - Exchange::ILifecycleManager::LifecycleState newLifecycleState = ((State*)context->getState())->getValue(); - if (isStateTerminating) - { - newLifecycleState = statePath[stateIndex]; - } - sendEvent(context, oldLifecycleState, newLifecycleState, errorReason); - - if (isStateTerminating) - { - result = updateState(context, statePath[stateIndex], errorReason); - if(result) - { - printf("StateHandler::changeState:Terminating: Success %s -> %s\n", mStateStrings[oldLifecycleState].c_str(), mStateStrings[statePath[stateIndex]].c_str()); - } - else - { - printf("StateHandler::changeState:Terminating: Failed to change state from %s to %s\n", mStateStrings[oldLifecycleState].c_str(), mStateStrings[statePath[stateIndex]].c_str()); - break; - } - if (true == context->mPendingStateTransition) - { - lastStateIndex = stateIndex; - break; - } - } - } - if (true == context->mPendingStateTransition) - { - context->mPendingStates.clear(); - if (lastStateIndex < statePath.size()) - { - for (size_t stateIndex = lastStateIndex; stateIndex < statePath.size() ; stateIndex++) - { - context->mPendingStates.push_back(statePath[stateIndex]); - } - } - } - else - { - context->mPendingStateTransition = false; - context->mPendingEventName = ""; - context->mPendingStates.clear(); - } - return result; - } - - void StateHandler::sendEvent(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState oldLifecycleState, Exchange::ILifecycleManager::LifecycleState newLifecycleState, string& errorReason) - { - IEventHandler* eventHandler = RequestHandler::getInstance()->getEventHandler(); - - if (nullptr != eventHandler) - { - struct timespec stateChangeTime; - timespec_get(&stateChangeTime, TIME_UTC); - context->setLastLifecycleStateChangeTime(stateChangeTime); - context->setStateChangeId(sStateChangeCount); - sStateChangeCount++; - - JsonObject eventData; - eventData["appId"] = context->getAppId(); - eventData["appInstanceId"] = context->getAppInstanceId(); - eventData["oldLifecycleState"] = (uint32_t)oldLifecycleState; - eventData["newLifecycleState"] = (uint32_t)newLifecycleState; - if (newLifecycleState == Exchange::ILifecycleManager::LifecycleState::ACTIVE) - { - eventData["navigationIntent"] = context->getMostRecentIntent(); - } - eventData["errorReason"] = errorReason; - eventHandler->onStateChangeEvent(eventData); - } - } - - bool StateHandler::getStatePath(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifecycleState, std::vector& statePath, string& errorReason) - { - if (false == context->mPendingStateTransition) - { - Exchange::ILifecycleManager::LifecycleState currentLifecycleState = context->getCurrentLifecycleState(); - std::map seenPaths; - - bool isValidRequest = StateHandler::isValidTransition(currentLifecycleState, lifecycleState, seenPaths, statePath); - if (!isValidRequest) - { - errorReason = "Invalid launch request in current state"; - return false; - } - //ensure final state is pushed here - statePath.push_back(lifecycleState); - - if (Exchange::ILifecycleManager::LifecycleState::TERMINATING == lifecycleState) - { - statePath.push_back(Exchange::ILifecycleManager::LifecycleState::UNLOADED); - } - } - else - { - statePath = context->mPendingStates; - } - return true; - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/StateHandler.h b/LifecycleManager/StateHandler.h deleted file mode 100644 index ce0d781..0000000 --- a/LifecycleManager/StateHandler.h +++ /dev/null @@ -1,52 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include "ApplicationContext.h" -#include "State.h" -#include -#include -#include -#include "StateTransitionRequest.h" - -namespace WPEFramework -{ - namespace Plugin - { - class StateHandler - { - public: - static void initialize(); - static bool changeState(StateTransitionRequest& request, string& errorReason); - - private: - static uint32_t sStateChangeCount; - - static State* createState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifeCycleState); - static bool isValidTransition(Exchange::ILifecycleManager::LifecycleState start, Exchange::ILifecycleManager::LifecycleState target, std::map& pathSequence, std::vector& foundPath); - static bool updateState(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifeCycleState, string& errorReason); - static void sendEvent(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState oldLifecycleState, Exchange::ILifecycleManager::LifecycleState newLifecycleState, string& errorReason); - static bool getStatePath(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState lifecycleState, std::vector& statePath, string& errorReason); - static std::map> mPossibleStateTransitions; - static std::map mStateStrings; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/StateTransitionHandler.cpp b/LifecycleManager/StateTransitionHandler.cpp deleted file mode 100644 index c9930c2..0000000 --- a/LifecycleManager/StateTransitionHandler.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "StateTransitionHandler.h" -#include "StateHandler.h" -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - static std::thread requestHandlerThread; - std::mutex gRequestMutex; - sem_t gRequestSemaphore; - std::vector> gRequests; - static bool sRunning = true; - - StateTransitionHandler* StateTransitionHandler::mInstance = nullptr; - - StateTransitionHandler* StateTransitionHandler::getInstance() - { - if (nullptr == mInstance) - { - mInstance = new StateTransitionHandler(); - } - return mInstance; - } - - StateTransitionHandler::StateTransitionHandler() - { - } - - StateTransitionHandler::~StateTransitionHandler() - { - } - - bool StateTransitionHandler::initialize() - { - sRunning = true; - StateHandler::initialize(); - sem_init(&gRequestSemaphore, 0, 0); - requestHandlerThread = std::thread([=]() { - bool isRunning = true; - gRequestMutex.lock(); - isRunning = sRunning; - gRequestMutex.unlock(); - while(isRunning) - { - gRequestMutex.lock(); - while (gRequests.size() > 0) - { - std::shared_ptr request = gRequests.front(); - if (!request) - { - gRequests.erase(gRequests.begin()); - continue; - } - std::string errorReason; - bool success = StateHandler::changeState(*request, errorReason); - if (!success) - { - printf("ERROR IN STATE TRANSITION ... %s\n",errorReason.c_str()); - fflush(stdout); - //TODO: Decide on what to do on state transition error - break; - } - gRequests.erase(gRequests.begin()); - } - gRequestMutex.unlock(); - sem_wait(&gRequestSemaphore); - gRequestMutex.lock(); - isRunning = sRunning; - gRequestMutex.unlock(); - } - }); - return true; - } - - void StateTransitionHandler::terminate() - { - gRequestMutex.lock(); - sRunning = false; - gRequestMutex.unlock(); - sem_post(&gRequestSemaphore); - requestHandlerThread.join(); - } - - void StateTransitionHandler::addRequest(StateTransitionRequest& request) - { - //TODO: Pass contect and state as argument to function - std::shared_ptr stateTransitionRequest = std::make_shared(request.mContext, request.mTargetState); - gRequestMutex.lock(); - gRequests.push_back(stateTransitionRequest); - gRequestMutex.unlock(); - sem_post(&gRequestSemaphore); - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/StateTransitionHandler.h b/LifecycleManager/StateTransitionHandler.h deleted file mode 100644 index 7537a4c..0000000 --- a/LifecycleManager/StateTransitionHandler.h +++ /dev/null @@ -1,45 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "ApplicationContext.h" -#include -#include "StateTransitionRequest.h" - -namespace WPEFramework -{ - namespace Plugin - { - class StateTransitionHandler - { - public: - StateTransitionHandler(const StateTransitionHandler& obj) = delete; - static StateTransitionHandler* getInstance(); - ~StateTransitionHandler (); - bool initialize(); - void terminate(); - void addRequest(StateTransitionRequest& request); - private: /* members */ - StateTransitionHandler(); - static StateTransitionHandler* mInstance; - //std::vector mRequests; //TODO - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/LifecycleManager/StateTransitionRequest.h b/LifecycleManager/StateTransitionRequest.h deleted file mode 100644 index 9f4df60..0000000 --- a/LifecycleManager/StateTransitionRequest.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef STATE_TRANSITION_REQUEST_H -#define STATE_TRANSITION_REQUEST_H -#include "ApplicationContext.h" -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - struct StateTransitionRequest - { - StateTransitionRequest(ApplicationContext* context, Exchange::ILifecycleManager::LifecycleState state): mContext(context), mTargetState(state), mStatePath() - { - } - ApplicationContext* mContext; - Exchange::ILifecycleManager::LifecycleState mTargetState; - std::vector mStatePath; - }; - } -} -#endif diff --git a/LifecycleManager/WindowManagerHandler.cpp b/LifecycleManager/WindowManagerHandler.cpp deleted file mode 100644 index 1a0457e..0000000 --- a/LifecycleManager/WindowManagerHandler.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "WindowManagerHandler.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { - -WindowManagerHandler::WindowManagerHandler() -: mWindowManager(nullptr), mWindowManagerNotification(*this), mEventHandler(nullptr) -{ - LOGINFO("Create WindowManagerHandler Instance"); -} - -WindowManagerHandler::~WindowManagerHandler() -{ - LOGINFO("Delete WindowManagerHandler Instance"); -} - -bool WindowManagerHandler::initialize(PluginHost::IShell* service, IEventHandler* eventHandler) -{ - bool ret = false; - mEventHandler = eventHandler; - mWindowManager = service->QueryInterfaceByCallsign("org.rdk.RDKWindowManager"); - if (mWindowManager != nullptr) - { - ret = true; - Core::hresult registerResult = mWindowManager->Register(&mWindowManagerNotification); - if (Core::ERROR_NONE != registerResult) - { - LOGINFO("Unable to register with windowmanager [%d] \n", registerResult); - } - } - else - { - LOGERR("windowmanager is null \n"); - } - return ret; -} - -void WindowManagerHandler::terminate() -{ - Core::hresult unregisterResult = mWindowManager->Unregister(&mWindowManagerNotification); - if (Core::ERROR_NONE != unregisterResult) - { - LOGINFO("Unable to unregister from runtimemanager [%d] \n", unregisterResult); - } - uint32_t result = mWindowManager->Release(); - LOGINFO("Window manager releases [%d]\n", result); - mWindowManager = nullptr; -} - -void WindowManagerHandler::WindowManagerNotification::OnUserInactivity(const double minutes) -{ - printf(" Received onUserInactivity event for %f minutes \n", minutes); - fflush(stdout); - JsonObject eventData; - eventData["minutes"] = minutes; - eventData["name"] = "onUserInactivity"; - _parent.onEvent(eventData); -} - -void WindowManagerHandler::WindowManagerNotification::OnDisconnected(const std::string& client) -{ - printf(" Received onDisconnect event for client[%s] \n", client.c_str()); - fflush(stdout); - JsonObject eventData; - eventData["client"] = client; - eventData["name"] = "onDisconnect"; - _parent.onEvent(eventData); -} - -void WindowManagerHandler::onEvent(JsonObject& data) -{ - if (mEventHandler) - { - mEventHandler->onWindowManagerEvent(data); - } -} - -Core::hresult WindowManagerHandler::renderReady(std::string appInstanceId, bool& isReady) -{ - Core::hresult renderReadyResult = mWindowManager->RenderReady(appInstanceId, isReady); - if (Core::ERROR_NONE != renderReadyResult) - { - printf("unable to get render ready from window manager [%d] \n", renderReadyResult); - fflush(stdout); - } - return renderReadyResult; -} - -Core::hresult WindowManagerHandler::enableDisplayRender(std::string appInstanceId, bool render) -{ - Core::hresult enableDisplayRenderResult = mWindowManager->EnableDisplayRender(appInstanceId, render); - if (Core::ERROR_NONE != enableDisplayRenderResult) - { - printf("unable to perform enable display renderer from window manager [%d] \n", enableDisplayRenderResult); - fflush(stdout); - } - return enableDisplayRenderResult; -} - -void WindowManagerHandler::WindowManagerNotification::OnReady(const std::string &client) -{ - printf("Received onReady event for app[%s] \n", client.c_str()); - fflush(stdout); - JsonObject eventData; - eventData["appInstanceId"] = client; - eventData["name"] = "onReady"; - _parent.onEvent(eventData); -} - -} // namespace Plugin -} // namespace WPEFramework diff --git a/LifecycleManager/WindowManagerHandler.h b/LifecycleManager/WindowManagerHandler.h deleted file mode 100644 index 94be195..0000000 --- a/LifecycleManager/WindowManagerHandler.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#include -#include -#include -#include "IEventHandler.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - class WindowManagerHandler - { - class WindowManagerNotification : public Exchange::IRDKWindowManager::INotification - { - private: - WindowManagerNotification(const WindowManagerNotification&) = delete; - WindowManagerNotification& operator=(const WindowManagerNotification&) = delete; - - public: - explicit WindowManagerNotification(WindowManagerHandler& parent) - : _parent(parent) - { - } - - ~WindowManagerNotification() override = default; - BEGIN_INTERFACE_MAP(WindowManagerNotification) - INTERFACE_ENTRY(Exchange::IRDKWindowManager::INotification) - END_INTERFACE_MAP - - virtual void OnUserInactivity(const double minutes) override; - virtual void OnDisconnected(const std::string& client) override; - virtual void OnReady(const std::string &client) override; - - private: - WindowManagerHandler& _parent; - }; - public: - WindowManagerHandler(); - ~WindowManagerHandler(); - - // We do not allow this plugin to be copied !! - WindowManagerHandler(const WindowManagerHandler&) = delete; - WindowManagerHandler& operator=(const WindowManagerHandler&) = delete; - - public: - bool initialize(PluginHost::IShell* service, IEventHandler* eventHandler); - void terminate(); - void onEvent(JsonObject& data); - Core::hresult renderReady(std::string appInstanceId, bool& isReady); - Core::hresult enableDisplayRender(std::string appInstanceId, bool render); - private: - Exchange::IRDKWindowManager* mWindowManager; - Core::Sink mWindowManagerNotification; - IEventHandler* mEventHandler; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/MessageControl/CHANGELOG.md b/MessageControl/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/MessageControl/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/MessageControl/CMakeLists.txt b/MessageControl/CMakeLists.txt deleted file mode 100644 index 6fc1d7a..0000000 --- a/MessageControl/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(MessageControl) - -cmake_minimum_required(VERSION 3.3) - -find_package(WPEFramework) - -project_version(1.0.0) - -set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) - -message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") - -set(PLUGIN_MESSAGECONTROL_AUTOSTART true CACHE STRING "Automatically start plugin") -set(PLUGIN_MESSAGECONTROL_ABBREVIATED true CACHE STRING "Display abbreviated messages") -set(PLUGIN_MESSAGECONTROL_MAX_EXPORTCONNECTIONS 5 CACHE STRING "Maximum allowed export connections") -set(PLUGIN_MESSAGECONTROL_REMOTE "false" CACHE STRING "Remote binding details enabled") -set(PLUGIN_MESSAGECONTROL_PORT "0" CACHE STRING "PORT address") -set(PLUGIN_MESSAGECONTROL_BINDING "0.0.0.0" CACHE STRING "Binding IP Address") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(${NAMESPACE}Messaging REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - MessageControl.cpp - MessageOutput.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions - ${NAMESPACE}Messaging::${NAMESPACE}Messaging) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config() diff --git a/MessageControl/MessageControl.conf.in b/MessageControl/MessageControl.conf.in deleted file mode 100644 index 70d71d3..0000000 --- a/MessageControl/MessageControl.conf.in +++ /dev/null @@ -1,23 +0,0 @@ -autostart = "@PLUGIN_MESSAGECONTROL_AUTOSTART@" - -configuration = JSON() - -if boolean("@PLUGIN_MESSAGECONTROL_CONSOLE@"): - configuration.add("console", "@PLUGIN_MESSAGECONTROL_CONSOLE@") - -if boolean("@PLUGIN_MESSAGECONTROL_SYSLOG@"): - configuration.add("syslog", "@PLUGIN_MESSAGECONTROL_SYSLOG@") - -if boolean("@PLUGIN_MESSAGECONTROL_FILENAME@"): - configuration.add("filepath", "@PLUGIN_MESSAGECONTROL_FILENAME@") - -if boolean("@PLUGIN_MESSAGECONTROL_ABBREVIATED@"): - configuration.add("abbreviated", "@PLUGIN_MESSAGECONTROL_ABBREVIATED@") - -configuration.add("maxexportconnections", "@PLUGIN_MESSAGECONTROL_MAX_EXPORTCONNECTIONS@") - -if boolean("@PLUGIN_MESSAGECONTROL_REMOTE@"): - remote = JSON() - remote.add("port", "@PLUGIN_MESSAGECONTROL_PORT@") - remote.add("binding", "@PLUGIN_MESSAGECONTROL_BINDING@") - configuration.add("remote", remote) diff --git a/MessageControl/MessageControl.config b/MessageControl/MessageControl.config deleted file mode 100644 index 677a888..0000000 --- a/MessageControl/MessageControl.config +++ /dev/null @@ -1,31 +0,0 @@ -set(autostart ${PLUGIN_MESSAGECONTROL_AUTOSTART}) -map() - - if(PLUGIN_MESSAGECONTROL_CONSOLE) - kv(console ${PLUGIN_MESSAGECONTROL_CONSOLE}) - endif() - - if(PLUGIN_MESSAGECONTROL_SYSLOG) - kv(syslog ${PLUGIN_MESSAGECONTROL_SYSLOG}) - endif() - - if(PLUGIN_MESSAGECONTROL_FILENAME) - kv(filepath ${PLUGIN_MESSAGECONTROL_FILENAME}) - endif() - - if(PLUGIN_MESSAGECONTROL_ABBREVIATED) - kv(abbreviated ${PLUGIN_MESSAGECONTROL_ABBREVIATED}) - endif() - - kv(maxexportconnections ${PLUGIN_MESSAGECONTROL_MAX_EXPORTCONNECTIONS}) - - if(PLUGIN_MESSAGECONTROL_REMOTE) - key(remote) - map() - kv(port ${PLUGIN_MESSAGECONTROL_PORT}) - kv(binding ${PLUGIN_MESSAGECONTROL_BINDING}) - end() - endif() - -end() -ans(configuration) diff --git a/MessageControl/MessageControl.cpp b/MessageControl/MessageControl.cpp deleted file mode 100644 index d28304b..0000000 --- a/MessageControl/MessageControl.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MessageControl.h" -#include "MessageOutput.h" -#include - -namespace WPEFramework { - - namespace Plugin { - - namespace { - - static Metadata metadata( - // Version - 1, 0, 0, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - MessageControl::Config::NetworkNode::NetworkNode() - : Core::JSON::Container() - , Port(2200) - , Binding("0.0.0.0") - { - Add(_T("port"), &Port); - Add(_T("binding"), &Binding); - } - - MessageControl::Config::NetworkNode::NetworkNode(const NetworkNode& copy) - : Core::JSON::Container() - , Port(copy.Port) - , Binding(copy.Binding) - { - Add(_T("port"), &Port); - Add(_T("binding"), &Binding); - } - - MessageControl::MessageControl() - : _adminLock() - , _outputLock() - , _config() - , _outputDirector() - , _webSocketExporter() - , _callback(nullptr) - , _observer(*this) - , _service(nullptr) - , _dispatcherIdentifier(Messaging::MessageUnit::Instance().Identifier()) - , _dispatcherBasePath(Messaging::MessageUnit::Instance().BasePath()) - , _client(_dispatcherIdentifier, _dispatcherBasePath, Messaging::MessageUnit::Instance().SocketPort()) - , _worker(*this) - , _tracingFactory() - , _loggingFactory() - , _warningReportingFactory() - { - _client.AddInstance(0); - _client.AddFactory(Core::Messaging::Metadata::type::TRACING, &_tracingFactory); - _client.AddFactory(Core::Messaging::Metadata::type::LOGGING, &_loggingFactory); - _client.AddFactory(Core::Messaging::Metadata::type::REPORTING, &_warningReportingFactory); - } - - const string MessageControl::Initialize(PluginHost::IShell* service) - { - string message; - - ASSERT(service != nullptr); - - _config.Clear(); - _config.FromString(service->ConfigLine()); - - Core::Messaging::MessageInfo::abbreviate abbreviate; - - if (_config.Abbreviated.Value() == 0) { - abbreviate = Core::Messaging::MessageInfo::abbreviate::FULL; - } - else { - abbreviate = Core::Messaging::MessageInfo::abbreviate::ABBREVIATED; - } - - _service = service; - _service->AddRef(); - - if ((service->Background() == false) && (((_config.SysLog.IsSet() == false) && (_config.Console.IsSet() == false)) || (_config.Console.Value() == true))) { - Announce(new Publishers::ConsoleOutput(abbreviate)); - } - if ((service->Background() == true) && (((_config.SysLog.IsSet() == false) && (_config.Console.IsSet() == false)) || (_config.SysLog.Value() == true))) { - Announce(new Publishers::SyslogOutput(abbreviate)); - } - if (_config.FileName.Value().empty() == false) { - _config.FileName = service->VolatilePath() + _config.FileName.Value(); - Announce(new Publishers::FileOutput(abbreviate, _config.FileName.Value())); - } - if ((_config.Remote.Binding.Value().empty() == false) && (_config.Remote.Port.Value() != 0)) { - Announce(new Publishers::UDPOutput(Core::NodeId(_config.Remote.NodeId()))); - } - - _webSocketExporter.Initialize(service, _config.MaxExportConnections.Value()); - - Exchange::JMessageControl::Register(*this, this); - - _service->Register(&_observer); - - if (Callback(&_observer) != Core::ERROR_NONE) { - message = _T("MessageControl plugin could not be _configured."); - } - - return (message); - } - - void MessageControl::Deinitialize(VARIABLE_IS_NOT_USED PluginHost::IShell* service) - { - if (_service != nullptr) { - ASSERT (_service == service); - - Exchange::JMessageControl::Unregister(*this); - - Callback(nullptr); - - _service->Unregister(&_observer); - - _outputLock.Lock(); - - _webSocketExporter.Deinitialize(); - - _outputLock.Unlock(); - - while (_outputDirector.empty() == false) { - delete _outputDirector.back(); - _outputDirector.pop_back(); - } - - _service->Release(); - _service = nullptr; - } - } - - string MessageControl::Information() const { - // No additional info to report. - return (string()); - } - - bool MessageControl::Attach(PluginHost::Channel& channel) - { - TRACE(Trace::Information, (Core::Format(_T("Attaching channel ID [%d]"), channel.Id()).c_str())); - - return (_webSocketExporter.Attach(channel.Id())); - } - - void MessageControl::Detach(PluginHost::Channel& channel) - { - TRACE(Trace::Information, (Core::Format(_T("Detaching channel ID [%d]"), channel.Id()).c_str())); - _webSocketExporter.Detach(channel.Id()); - } - - Core::ProxyType MessageControl::Inbound(const string&) { - return (_webSocketExporter.Command()); - } - - Core::ProxyType MessageControl::Inbound(const uint32_t ID, const Core::ProxyType& element) { - return (Core::ProxyType(_webSocketExporter.Received(ID, element))); - } - -} // namespace Plugin -} diff --git a/MessageControl/MessageControl.h b/MessageControl/MessageControl.h deleted file mode 100644 index ab4e193..0000000 --- a/MessageControl/MessageControl.h +++ /dev/null @@ -1,469 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include "MessageOutput.h" -#include - -namespace WPEFramework { - -namespace Plugin { - - class MessageControl : public PluginHost::JSONRPC, public PluginHost::IPluginExtended, public PluginHost::IWebSocket, public Exchange::IMessageControl { - private: - using Cleanups = std::vector; - - class WorkerThread : public Core::Thread { - public: - WorkerThread() = delete; - WorkerThread(const WorkerThread&) = delete; - WorkerThread& operator= (const WorkerThread&) = delete; - - WorkerThread(MessageControl& parent) - : Core::Thread() - , _parent(parent) - { - } - ~WorkerThread() override = default; - - private: - uint32_t Worker() override - { - _parent.Dispatch(); - - return (Core::infinite); - } - - private: - MessageControl& _parent; - }; - - private: - struct ICollect { - - struct ICallback { - - virtual void Message(const Core::Messaging::MessageInfo& metadata, const string& text) = 0; - - virtual ~ICallback() = default; - }; - - virtual uint32_t Callback(ICallback* callback) = 0; - - virtual ~ICollect() = default; - }; - - private: - using OutputList = std::vector; - - class Config : public Core::JSON::Container { - private: - class NetworkNode : public Core::JSON::Container { - public: - NetworkNode(); - NetworkNode(const NetworkNode& copy); - ~NetworkNode() = default; - - public: - Core::NodeId NodeId() const { - return (Core::NodeId(Binding.Value().c_str(), Port.Value())); - } - - public: - Core::JSON::DecUInt16 Port; - Core::JSON::String Binding; - }; - - public: - Config() - : Core::JSON::Container() - , Console(false) - , SysLog(false) - , FileName() - , Abbreviated(true) - , MaxExportConnections(Publishers::WebSocketOutput::DefaultMaxConnections) - , Remote() - { - Add(_T("console"), &Console); - Add(_T("syslog"), &SysLog); - Add(_T("filepath"), &FileName); - Add(_T("abbreviated"), &Abbreviated); - Add(_T("maxexportconnections"), &MaxExportConnections); - Add(_T("remote"), &Remote); - } - ~Config() = default; - - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - Core::JSON::Boolean Console; - Core::JSON::Boolean SysLog; - Core::JSON::String FileName; - Core::JSON::Boolean Abbreviated; - Core::JSON::DecUInt16 MaxExportConnections; - NetworkNode Remote; - }; - - class Observer - : public RPC::IRemoteConnection::INotification - , public Plugin::MessageControl::ICollect::ICallback { - private: - enum state { - ATTACHING, - DETACHING, - OBSERVING - }; - using Observers = std::unordered_map; - - public: - Observer() = delete; - Observer(const Observer&) = delete; - Observer& operator= (const Observer&) = delete; - - explicit Observer(MessageControl& parent) - : _parent(parent) - , _adminLock() - , _observing() - , _job(*this) - { - } - ~Observer() override { - _job.Revoke(); - } - - public: - // - // Exchange::IMessageControl::INotification - // ---------------------------------------------------------- - void Message(const Core::Messaging::MessageInfo& metadata, const string& message) override { - _parent.Message(metadata, message); - } - - // - // RPC::IRemoteConnection::INotification - // ---------------------------------------------------------- - void Activated(RPC::IRemoteConnection* connection) override - { - uint32_t id = connection->Id(); - - _adminLock.Lock(); - - // Seems the ID is already in here, thats odd, and impossible :-) - Observers::iterator index = _observing.find(id); - - if (index == _observing.end()) { - _observing.emplace(std::piecewise_construct, - std::make_tuple(id), - std::make_tuple(state::ATTACHING)); - } - else if (index->second == state::DETACHING) { - index->second = state::OBSERVING; - } - - _adminLock.Unlock(); - - _job.Submit(); - } - - void Deactivated(RPC::IRemoteConnection* connection) override - { - ASSERT(connection != nullptr); - - RPC::IMonitorableProcess* controlled (connection->QueryInterface()); - - if (controlled != nullptr) { - // This is a connection that is controleld by WPEFramework. For this we can wait till we - // receive a terminated. - controlled->Release(); - } - else { - // We have no clue where this is coming from, just assume that if there are message files - // with this ID that it can be closed. - Drop(connection->Id()); - } - } - - void Terminated(RPC::IRemoteConnection* connection) override - { - ASSERT(connection != nullptr); - Drop(connection->Id()); - } - - BEGIN_INTERFACE_MAP(Observer) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - private: - friend class Core::ThreadPool::JobType; - - void Drop (const uint32_t id) - { - _adminLock.Lock(); - - // Seems the ID is already in here, thats odd, and impossible :-) - Observers::iterator index = _observing.find(id); - - ASSERT(index != _observing.end()); - - if (index != _observing.end()) { - if (index->second == state::ATTACHING) { - _observing.erase(index); - } - else if (index->second == state::OBSERVING) { - index->second = state::DETACHING; - } - } - - _adminLock.Unlock(); - - _job.Submit(); - } - - void Dispatch() - { - _adminLock.Lock(); - - bool done = false; - - while (done == false) { - Observers::iterator index = _observing.begin(); - - while (done == false) { - if (index->second == state::ATTACHING) { - const uint32_t id = index->first; - index->second = state::OBSERVING; - _adminLock.Unlock(); - _parent.Attach(id); - _adminLock.Lock(); - break; - } - else if (index->second == state::DETACHING) { - const uint32_t id = index->first; - _observing.erase(index); - _adminLock.Unlock(); - _parent.Detach(id); - _adminLock.Lock(); - break; - } - else { - index++; - - if (index == _observing.end()) { - done = true; - } - } - } - } - - _adminLock.Unlock(); - } - - private: - MessageControl& _parent; - Core::CriticalSection _adminLock; - Observers _observing; - Core::WorkerPool::JobType _job; - }; - - public: - MessageControl(const MessageControl&) = delete; - MessageControl& operator=(const MessageControl&) = delete; - - MessageControl(); - - ~MessageControl() override - { - _worker.Stop(); - _worker.Wait(Core::Thread::STOPPED, Core::infinite); - _client.ClearInstances(); - } - - BEGIN_INTERFACE_MAP(MessageControl) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_ENTRY(PluginHost::IPluginExtended) - INTERFACE_ENTRY(PluginHost::IWebSocket) - INTERFACE_ENTRY(Exchange::IMessageControl) - END_INTERFACE_MAP - - public: - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - bool Attach(PluginHost::Channel&) override; - void Detach(PluginHost::Channel&) override; - Core::ProxyType Inbound(const string& identifier) override; - Core::ProxyType Inbound(const uint32_t ID, const Core::ProxyType& element) override; - - private: - void Announce(Publishers::IPublish* output) - { - _outputLock.Lock(); - - ASSERT(std::find(_outputDirector.begin(), _outputDirector.end(), output) == _outputDirector.end()); - - _outputDirector.emplace_back(output); - - _outputLock.Unlock(); - } - - void Message(const Core::Messaging::MessageInfo& metadata, const string& message) - { - // Time to start sending it to all interested parties... - _outputLock.Lock(); - - for (auto& entry : _outputDirector) { - entry->Message(metadata, message); - } - - _webSocketExporter.Message(metadata, message); - - _outputLock.Unlock(); - } - - public: - uint32_t Callback(Plugin::MessageControl::ICollect::ICallback* callback) - { - _adminLock.Lock(); - - ASSERT((_callback != nullptr) ^ (callback != nullptr)); - - if (_callback != nullptr) { - _worker.Block(); - _client.SkipWaiting(); - _adminLock.Unlock(); - _worker.Wait(Core::Thread::BLOCKED, Core::infinite); - _adminLock.Lock(); - } - - _callback = callback; - - if (_callback != nullptr) { - _worker.Run(); - } - - _adminLock.Unlock(); - - return (Core::ERROR_NONE); - } - - void Attach(const uint32_t id) - { - _adminLock.Lock(); - - _client.AddInstance(id); - Cleanup(); - - _adminLock.Unlock(); - } - - void Detach(const uint32_t id) - { - _adminLock.Lock(); - - _client.RemoveInstance(id); - _cleaning.emplace_back(id); - Cleanup(); - - _adminLock.Unlock(); - } - - public: - void Cleanup() - { - // Also have a list through the cleanup we should do, just to make sure - Cleanups::iterator index = _cleaning.begin(); - - while (index != _cleaning.end()) { - bool destructed = true; - string filter (_dispatcherIdentifier + '.' + Core::NumberType(*index).Text() + _T(".*")); - Core::Directory directory (_dispatcherBasePath.c_str(), filter.c_str()); - - while ((destructed == true) && (directory.Next() == true)) { - Core::File file (directory.Current()); - destructed = destructed && (Core::File(directory.Current()).Destroy()); - } - - if (destructed == true) { - index = _cleaning.erase(index); - } - else { - index++; - } - } - } - - Core::hresult Enable(const MessageType type, const string& category, const string& module, const bool enabled) override - { - _client.Enable({static_cast(type), category, module}, enabled); - - return (Core::ERROR_NONE); - } - - Core::hresult Controls(Exchange::IMessageControl::IControlIterator*& controls) const override - { - std::list list; - Messaging::MessageUnit::Iterator index; - _client.Controls(index); - - while (index.Next() == true) { - list.push_back( { static_cast(index.Type()), index.Category(), index.Module(), index.Enabled() } ); - } - - using Implementation = RPC::IteratorType; - controls = Core::Service::Create(list); - - return (Core::ERROR_NONE); - } - - private: - void Dispatch() - { - _client.WaitForUpdates(Core::infinite); - - _client.PopMessagesAndCall([this](const Core::ProxyType& metadata, const Core::ProxyType& message) { - // Turn data into piecies to trasfer over the wire - Message(*metadata, message->Data()); - }); - } - - private: - Core::CriticalSection _adminLock; - Core::CriticalSection _outputLock; - Config _config; - OutputList _outputDirector; - Publishers::WebSocketOutput _webSocketExporter; - MessageControl::ICollect::ICallback* _callback; - Core::Sink _observer; - PluginHost::IShell* _service; - const string _dispatcherIdentifier; - const string _dispatcherBasePath; - Messaging::MessageClient _client; - WorkerThread _worker; - Messaging::TraceFactoryType _tracingFactory; - Messaging::TraceFactoryType _loggingFactory; - Messaging::TraceFactoryType _warningReportingFactory; - Cleanups _cleaning; - }; - -} // namespace Plugin -} diff --git a/MessageControl/MessageControl.vcxproj b/MessageControl/MessageControl.vcxproj deleted file mode 100644 index 78f5ed0..0000000 --- a/MessageControl/MessageControl.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {ACA665CC-3DFA-4C67-A6F4-2DF827A9378A} - Win32Proj - MessageControl - 10.0 - - - - DynamicLibrary - true - v143 - MultiByte - - - DynamicLibrary - false - v143 - true - MultiByte - - - DynamicLibrary - true - v143 - MultiByte - - - DynamicLibrary - false - v143 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - true - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - false - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - false - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - - NotUsing - Level3 - Disabled - true - _CRT_SECURE_NO_WARNINGS;_DEBUG;TRACECONTROL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - true - - - Windows - true - $(OutDir) - - - - - NotUsing - Level3 - Disabled - true - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;TRACECONTROL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - true - - - Windows - true - $(OutDir) - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;TRACECONTROL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - true - - - Windows - true - true - true - $(OutDir) - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;TRACECONTROL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - true - - - Windows - true - true - true - $(OutDir) - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MessageControl/MessageControl.vcxproj.filters b/MessageControl/MessageControl.vcxproj.filters deleted file mode 100644 index 75e3e0d..0000000 --- a/MessageControl/MessageControl.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - {2b6ccb25-f586-4a44-9592-dfb31982e7ef} - - - {06617fda-b01a-4420-9ac9-7cb45a8437a4} - - - \ No newline at end of file diff --git a/MessageControl/MessageControlImplementation.cpp b/MessageControl/MessageControlImplementation.cpp deleted file mode 100644 index 35a45e9..0000000 --- a/MessageControl/MessageControlImplementation.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MessageOutput.h" -#include "Module.h" -#include - -namespace WPEFramework { - -namespace { - - class MessageSettings : public Messaging::MessageUnit::Settings { - private: - MessageSettings() { - Messaging::MessageUnit::Settings::Load(); - }; - - public: - MessageSettings(const MessageSettings&) = delete; - MessageSettings& operator= (const MessageSettings&) = delete; - - static MessageSettings& Instance() { - static MessageSettings singleton; - return (singleton); - } - }; -} - -namespace Plugin { - - class MessageControlImplementation : public Exchange::IMessageControl, public Exchange::IMessageControl::ICollect { - private: - class WorkerThread : public Core::Thread { - public: - WorkerThread() = delete; - WorkerThread(const WorkerThread&) = delete; - WorkerThread& operator= (const WorkerThread&) = delete; - - WorkerThread(MessageControlImplementation& parent) - : Core::Thread() - , _parent(parent) - { - } - ~WorkerThread() override = default; - - private: - uint32_t Worker() override - { - _parent.Dispatch(); - - return (Core::infinite); - } - - private: - MessageControlImplementation& _parent; - }; - - public: - MessageControlImplementation(const MessageControlImplementation&) = delete; - MessageControlImplementation& operator=(const MessageControlImplementation&) = delete; - - MessageControlImplementation() - : _adminLock() - , _callback(nullptr) - , _dispatcherIdentifier(MessageSettings::Instance().Identifier()) - , _dispatcherBasePath(MessageSettings::Instance().BasePath()) - , _worker(*this) - , _client(_dispatcherIdentifier, _dispatcherBasePath, MessageSettings::Instance().SocketPort()) - , _factory() - { - _client.AddInstance(0); - _client.AddFactory(Core::Messaging::Metadata::type::TRACING, &_factory); - _client.AddFactory(Core::Messaging::Metadata::type::LOGGING, &_factory); - } - - ~MessageControlImplementation() override - { - ASSERT(_callback == nullptr); - - _worker.Stop(); - _worker.Wait(Core::Thread::STOPPED, Core::infinite); - _client.ClearInstances(); - } - - public: - uint32_t Callback(Exchange::IMessageControl::ICollect::ICallback* callback) override - { - _adminLock.Lock(); - - ASSERT((_callback != nullptr) ^ (callback != nullptr)); - - if (_callback != nullptr) { - - _worker.Block(); - _client.SkipWaiting(); - - _adminLock.Unlock(); - - _worker.Wait(Core::Thread::BLOCKED, Core::infinite); - - _adminLock.Lock(); - - _callback->Release(); - } - _callback = callback; - - if (_callback != nullptr) { - _callback->AddRef(); - _worker.Run(); - } - - _adminLock.Unlock(); - - return (Core::ERROR_NONE); - } - - uint32_t Attach(const uint32_t id) override - { - _adminLock.Lock(); - _client.AddInstance(id); - _adminLock.Unlock(); - - return (Core::ERROR_NONE); - } - - uint32_t Detach(const uint32_t id) override - { - _adminLock.Lock(); - _client.RemoveInstance(id); - _adminLock.Unlock(); - - return (Core::ERROR_NONE); - } - - Core::hresult Enable(const MessageType type, const string& category, const string& module, const bool enabled) override - { - _client.Enable({static_cast(type), category, module}, enabled); - - return (Core::ERROR_NONE); - } - - Core::hresult Controls(Exchange::IMessageControl::IControlIterator*& controls) const override - { - std::list list; - Messaging::MessageUnit::Iterator index; - - _client.Controls(index); - - while (index.Next() == true) { - list.push_back( { static_cast(index.Type()), index.Category(), index.Module(), index.Enabled() } ); - } - - using Implementation = RPC::IteratorType; - controls = Core::Service::Create(list); - - return (Core::ERROR_NONE); - } - - public: - BEGIN_INTERFACE_MAP(MessageControlImplementation) - INTERFACE_ENTRY(Exchange::IMessageControl) - INTERFACE_ENTRY(Exchange::IMessageControl::ICollect) - END_INTERFACE_MAP - - private: - void Dispatch() - { - _client.WaitForUpdates(Core::infinite); - - _client.PopMessagesAndCall([this](const Core::Messaging::IStore::Information& info, const Core::ProxyType& message) { - ASSERT(_callback != nullptr); - - // Turn data into piecies to trasfer over the wire - _callback->Message(static_cast(info.Type()), info.Module(), info.Category(), info.FileName(), info.LineNumber(), info.ClassName(), info.TimeStamp(), message->Data()); - }); - } - - private: - Core::CriticalSection _adminLock; - IMessageControl::ICollect::ICallback* _callback; - - const string _dispatcherIdentifier; - const string _dispatcherBasePath; - - WorkerThread _worker; - Messaging::MessageClient _client; - Messaging::TraceFactory _factory; - }; - - SERVICE_REGISTRATION(MessageControlImplementation, 1, 0); - -} // namespace Plugin -} diff --git a/MessageControl/MessageOutput.cpp b/MessageControl/MessageOutput.cpp deleted file mode 100644 index 430bea0..0000000 --- a/MessageControl/MessageOutput.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MessageOutput.h" - -namespace WPEFramework { - -namespace Publishers { - - string Text::Convert(const Core::Messaging::MessageInfo& metadata, const string& text) /* override */ - { - ASSERT(metadata.Type() != Core::Messaging::Metadata::type::INVALID); - - string output = metadata.ToString(_abbreviated).c_str() + - Core::Format("%s\n", text.c_str()); - - return (output); - } - - void ConsoleOutput::Message(const Core::Messaging::MessageInfo& metadata, const string& text) /* override */ - { - std::cout << _convertor.Convert(metadata, text); - } - - void SyslogOutput::Message(const Core::Messaging::MessageInfo& metadata, const string& text) /* override */ - { -#ifndef __WINDOWS__ - syslog(LOG_NOTICE, _T("%s"), _convertor.Convert(metadata, text).c_str()); -#else - printf(_T("%s"), _convertor.Convert(metadata, text).c_str()); -#endif - } - - void FileOutput::Message(const Core::Messaging::MessageInfo& metadata, const string& text) /* override */ - { - if (_file.IsOpen()) { - const string line = _convertor.Convert(metadata, text); - _file.Write(reinterpret_cast(line.c_str()), static_cast(line.length())); - } - } - - void JSON::Convert(const Core::Messaging::MessageInfo& metadata, const string& text, Data& data) - { - ExtraOutputOptions options = _outputOptions; - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::PAUSED)) == 0) { - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::CATEGORY)) != 0) { - data.Category = metadata.Category(); - } - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::MODULE)) != 0) { - data.Module = metadata.Module(); - } - - if (metadata.Type() == Core::Messaging::Metadata::type::TRACING) { - ASSERT(dynamic_cast(&metadata) != nullptr); - const Core::Messaging::IStore::Tracing& trace = static_cast(metadata); - const Core::Time now(trace.TimeStamp()); - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::INCLUDINGDATE)) != 0) { - data.Time = now.ToRFC1123(true); - } - else { - data.Time = now.ToTimeOnly(true); - } - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::FILENAME)) != 0) { - data.FileName = trace.FileName(); - } - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::LINENUMBER)) != 0) { - data.LineNumber = trace.LineNumber(); - } - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::CLASSNAME)) != 0) { - data.ClassName = trace.ClassName(); - } - } - else if (metadata.Type() == Core::Messaging::Metadata::type::LOGGING) { - ASSERT(dynamic_cast(&metadata) != nullptr); - const Core::Messaging::IStore::Logging& log = static_cast(metadata); - const Core::Time now(log.TimeStamp()); - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::INCLUDINGDATE)) != 0) { - data.Time = now.ToRFC1123(true); - } - else { - data.Time = now.ToTimeOnly(true); - } - } - else if (metadata.Type() == Core::Messaging::Metadata::type::REPORTING) { - ASSERT(dynamic_cast(&metadata) != nullptr); - const Core::Messaging::IStore::WarningReporting& report = static_cast(metadata); - const Core::Time now(report.TimeStamp()); - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::INCLUDINGDATE)) != 0) { - data.Time = now.ToRFC1123(true); - } - else { - data.Time = now.ToTimeOnly(true); - } - - if ((AsNumber(options) & AsNumber(ExtraOutputOptions::CALLSIGN)) != 0) { - data.Callsign = report.Callsign(); - } - } - else { - ASSERT(metadata.Type() != Core::Messaging::Metadata::type::INVALID); - } - - data.Message = text; - } - } - - //UDPOutput - UDPOutput::Channel::Channel(const Core::NodeId& nodeId) - : Core::SocketDatagram(false, nodeId.Origin(), nodeId, Messaging::MessageUnit::DataSize, 0) - , _loaded(0) - { - } - UDPOutput::Channel::~Channel() { - Close(Core::infinite); - } - - uint16_t UDPOutput::Channel::SendData(uint8_t* dataFrame, const uint16_t maxSendSize) - { - _adminLock.Lock(); - - uint16_t actualByteCount = (_loaded > maxSendSize ? maxSendSize : _loaded); - memcpy(dataFrame, _sendBuffer, actualByteCount); - _loaded = 0; - - _adminLock.Unlock(); - - return (actualByteCount); - } - - //unused - uint16_t UDPOutput::Channel::ReceiveData(uint8_t*, const uint16_t) { - return 0; - } - - void UDPOutput::Channel::StateChange() - { - } - - void UDPOutput::Channel::Output(const Core::Messaging::Metadata& metadata, const Core::Messaging::IEvent* message) - { - _adminLock.Lock(); - - uint16_t length = 0; - ASSERT(metadata.Type() != Core::Messaging::Metadata::INVALID); - - length += metadata.Serialize(_sendBuffer + length, sizeof(_sendBuffer) - length); - length += message->Serialize(_sendBuffer + length, sizeof(_sendBuffer) - length); - _loaded = length; - - _adminLock.Unlock(); - - Trigger(); - } - - UDPOutput::UDPOutput(const Core::NodeId& nodeId) - : _output(nodeId) { - _output.Open(0); - } - - void UDPOutput::Message(const Core::Messaging::MessageInfo& metadata, const string& text) /* override */ - { - //yikes, recreating stuff from received pieces - Messaging::TextMessage textMessage(text); - _output.Output(metadata, &textMessage); - } - -} // namespace Publishers -} diff --git a/MessageControl/MessageOutput.h b/MessageControl/MessageOutput.h deleted file mode 100644 index de9def2..0000000 --- a/MessageControl/MessageOutput.h +++ /dev/null @@ -1,575 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include "Module.h" - -namespace WPEFramework { - -namespace Publishers { - - struct IPublish { - virtual ~IPublish() = default; - - virtual void Message(const Core::Messaging::MessageInfo& metadata, const string& text) = 0; - }; - - class Text { - public: - Text() = delete; - Text(const Text&) = delete; - Text& operator=(const Text&) = delete; - - explicit Text(const Core::Messaging::MessageInfo::abbreviate abbreviated) - : _abbreviated(abbreviated) - { - } - ~Text() = default; - - public: - string Convert (const Core::Messaging::MessageInfo& metadata, const string& text); - - private: - Core::Messaging::MessageInfo::abbreviate _abbreviated; - }; - - class ConsoleOutput : public IPublish { - public: - ConsoleOutput() = delete; - ConsoleOutput(const ConsoleOutput&) = delete; - ConsoleOutput& operator=(const ConsoleOutput&) = delete; - - explicit ConsoleOutput(const Core::Messaging::MessageInfo::abbreviate abbreviate) - : _convertor(abbreviate) - { - } - ~ConsoleOutput() override = default; - - public: - void Message(const Core::Messaging::MessageInfo& metadata, const string& text); - - private: - Text _convertor; - }; - - class SyslogOutput : public IPublish { - public: - SyslogOutput() = delete; - SyslogOutput(const SyslogOutput&) = delete; - SyslogOutput& operator=(const SyslogOutput&) = delete; - - explicit SyslogOutput(const Core::Messaging::MessageInfo::abbreviate abbreviate) - : _convertor(abbreviate) - { - } - ~SyslogOutput() override = default; - - public: - void Message(const Core::Messaging::MessageInfo& metadata, const string& text); - - private: - Text _convertor; - }; - - class FileOutput : public IPublish { - public: - FileOutput() = delete; - FileOutput(const FileOutput&) = delete; - FileOutput& operator=(const FileOutput&) = delete; - - explicit FileOutput(const Core::Messaging::MessageInfo::abbreviate abbreviate, const string& filepath) - : _convertor(abbreviate) - , _file(filepath) - { - _file.Create(); - - if (!_file.IsOpen()) { - TRACE(Trace::Error, (_T("Could not open file <%s>. Outputting warnings to file unavailable."), filepath)); - } - } - ~FileOutput() override - { - if (_file.IsOpen()) { - _file.Close(); - } - } - - public: - void Message(const Core::Messaging::MessageInfo& metadata, const string& text); - - private: - Text _convertor; - Core::File _file; - }; - - class JSON { - private: - enum class ExtraOutputOptions { - ABREVIATED = 0x00, - FILENAME = 0x01, - LINENUMBER = 0x03, // selecting LINENUMBER will automatically select FILENAME - CLASSNAME = 0x04, - MODULE = 0x08, - CATEGORY = 0x10, - CALLSIGN = 0x20, - INCLUDINGDATE = 0x40, - ALL = 0x7F, - PAUSED = 0x80 - }; - - public: - class Data : public Core::JSON::Container { - public: - Data(const Data&) = delete; - Data& operator=(const Data&) = delete; - - Data() - : Core::JSON::Container() - , Time() - , FileName() - , LineNumber() - , ClassName() - , Category() - , Module() - , Callsign() - , Message() - { - Add(_T("time"), &Time); - Add(_T("filename"), &FileName); - Add(_T("linenumber"), &LineNumber); - Add(_T("classname"), &ClassName); - Add(_T("category"), &Category); - Add(_T("module"), &Module); - Add(_T("callsign"), &Callsign); - Add(_T("message"), &Message); - } - ~Data() override = default; - - public: - Core::JSON::String Time; - Core::JSON::String FileName; - Core::JSON::DecUInt32 LineNumber; - Core::JSON::String ClassName; - Core::JSON::String Category; - Core::JSON::String Module; - Core::JSON::String Callsign; - Core::JSON::String Message; - }; - - public: - JSON(const JSON&) = delete; - JSON& operator=(const JSON&) = delete; - - JSON() - : _outputOptions(ExtraOutputOptions::ALL) - { - } - ~JSON() = default; - - public: - bool FileName() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::FILENAME)) != 0); - } - - void FileName(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::FILENAME)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::FILENAME)); - } - } - - bool LineNumber() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::LINENUMBER)) != 0); - } - - void LineNumber(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::LINENUMBER)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::LINENUMBER)); - } - } - - bool ClassName() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::CLASSNAME)) != 0); - } - - void ClassName(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::CLASSNAME)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::CLASSNAME)); - } - } - - bool Module() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::MODULE)) != 0); - } - - void Module(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::MODULE)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::MODULE)); - } - } - - bool Category() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::CATEGORY)) != 0); - } - - void Category(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::CATEGORY)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::CATEGORY)); - } - } - - bool Callsign() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::CALLSIGN)) != 0); - } - - void Callsign(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::CALLSIGN)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::CALLSIGN)); - } - } - - bool Date() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::INCLUDINGDATE)) != 0); - } - - void Date(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::INCLUDINGDATE)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::INCLUDINGDATE)); - } - } - - bool Paused() const { - return ((AsNumber(_outputOptions) & AsNumber(ExtraOutputOptions::PAUSED)) != 0); - } - - void Paused(const bool enabled) - { - if (enabled == true) { - _outputOptions = static_cast(AsNumber(_outputOptions) | AsNumber(ExtraOutputOptions::PAUSED)); - } - else { - _outputOptions = static_cast(AsNumber(_outputOptions) & ~AsNumber(ExtraOutputOptions::PAUSED)); - } - } - - void Convert(const Core::Messaging::MessageInfo& metadata, const string& text, Data& info); - - private: - template - static inline auto AsNumber(E t) -> typename std::underlying_type::type { - return (static_cast::type>(t)); - } - - private: - std::atomic _outputOptions; - }; - - class UDPOutput : public IPublish { - private: - class Channel : public Core::SocketDatagram { - public: - Channel() = delete; - Channel(const Channel&) = delete; - Channel& operator=(const Channel&) = delete; - - explicit Channel(const Core::NodeId& nodeId); - ~Channel() override; - - void Output(const Core::Messaging::Metadata& metadata, const Core::Messaging::IEvent* message); - - private: - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override; - // Unused - uint16_t ReceiveData(uint8_t*, const uint16_t) override; - void StateChange() override; - - uint8_t _sendBuffer[Messaging::MessageUnit::DataSize]; - uint16_t _loaded; - Core::CriticalSection _adminLock; - }; - - public: - UDPOutput() = delete; - UDPOutput(const UDPOutput&) = delete; - UDPOutput& operator=(const UDPOutput&) = delete; - - explicit UDPOutput(const Core::NodeId& nodeId); - ~UDPOutput() = default; - - void Message(const Core::Messaging::MessageInfo& metadata, const string& text); - - private: - Channel _output; - }; - - class WebSocketOutput : public IPublish { - private: - class ExportCommand : public Core::JSON::Container { - public: - ExportCommand(const ExportCommand&) = delete; - ExportCommand& operator=(const ExportCommand&) = delete; - - ExportCommand() - : Core::JSON::Container() - , FileName() - , LineNumber() - , Category() - , Module() - , Callsign() - , IncludingDate() - , Paused() - { - Add(_T("filename"), &FileName); - Add(_T("linenumber"), &LineNumber); - Add(_T("classname"), &ClassName); - Add(_T("category"), &Category); - Add(_T("module"), &Module); - Add(_T("callsign"), &Callsign); - Add(_T("includingdate"), &IncludingDate); - Add(_T("paused"), &Paused); - } - ~ExportCommand() override = default; - - public: - Core::JSON::Boolean FileName; - Core::JSON::Boolean LineNumber; - Core::JSON::Boolean ClassName; - Core::JSON::Boolean Category; - Core::JSON::Boolean Module; - Core::JSON::Boolean Callsign; - Core::JSON::Boolean IncludingDate; - Core::JSON::Boolean Paused; - }; - - using ChannelMap = std::unordered_map; - - public: - static constexpr uint16_t DefaultMaxConnections = 5; - - public: - WebSocketOutput(const WebSocketOutput& copy) = delete; - WebSocketOutput& operator=(const WebSocketOutput&) = delete; - - explicit WebSocketOutput() - : _lock() - , _server(nullptr) - , _channels() - , _maxExportConnections(0) - , _jsonExportDataFactory(2) - , _jsonExportCommandFactory(2) - { - } - ~WebSocketOutput() override = default; - - public: - void Initialize(PluginHost::IShell* service, const uint32_t maxConnections = DefaultMaxConnections) - { - _lock.Lock(); - - _server = service; - _server->AddRef(); - _maxExportConnections = maxConnections; - - _lock.Unlock(); - } - - void Deinitialize() - { - _lock.Lock(); - - _server->Release(); - _server = nullptr; - _channels.clear(); - _maxExportConnections = 0; - - _lock.Unlock(); - } - - bool Attach(const uint32_t id) - { - bool accepted = false; - _lock.Lock(); - - if (_channels.size() < _maxExportConnections) { - - ASSERT(_channels.find(id) == _channels.end()); - - _channels.emplace(std::piecewise_construct, - std::forward_as_tuple(id), - std::forward_as_tuple()); - - accepted = true; - } - - _lock.Unlock(); - - return (accepted); - } - - bool Detach(const uint32_t id) - { - bool deactivated = false; - - _lock.Lock(); - - ChannelMap::iterator index = _channels.find(id); - - if (index != _channels.end()) { - _channels.erase(index); - deactivated = true; - } - - _lock.Unlock(); - - return (deactivated); - } - - uint32_t MaxConnections() const { - return (_maxExportConnections); - } - - Core::ProxyType Received(const uint32_t id, const Core::ProxyType& element) - { - Core::ProxyType info = Core::ProxyType(element); - - if (info.IsValid() == false) { - element.Release(); - } - else { - _lock.Lock(); - - ChannelMap::iterator index = _channels.find(id); - - if (index != _channels.end()) { - if (info->FileName.IsSet() == true) { - index->second.FileName(info->FileName == true); - } - if (info->LineNumber.IsSet() == true) { - index->second.LineNumber(info->LineNumber == true); - } - if (info->ClassName.IsSet() == true) { - index->second.ClassName(info->ClassName == true); - } - if (info->Category.IsSet() == true) { - index->second.Category(info->Category == true); - } - if (info->Module.IsSet() == true) { - index->second.Module(info->Module == true); - } - if (info->Callsign.IsSet() == true) { - index->second.Callsign(info->Callsign == true); - } - if (info->IncludingDate.IsSet() == true) { - index->second.Date(info->IncludingDate == true); - } - if (info->Paused.IsSet() == true) { - index->second.Paused(info->Paused == true); - } - - info->Clear(); - info->FileName = index->second.FileName(); - info->LineNumber = index->second.LineNumber(); - info->ClassName = index->second.ClassName(); - info->Category = index->second.Category(); - info->Module = index->second.Module(); - info->Callsign = index->second.Callsign(); - info->IncludingDate = index->second.Date(); - info->Paused = index->second.Paused(); - } - - _lock.Unlock(); - } - - return (element); - } - - void Message(const Core::Messaging::MessageInfo& metadata, const string& text) override - { - std::list>> cachedList; - PluginHost::IShell* server = nullptr; - - _lock.Lock(); - - if (_server != nullptr) { - for (auto& item : _channels) { - if (item.second.Paused() == false) { - Core::ProxyType data = _jsonExportDataFactory.Element(); - item.second.Convert(metadata, text, *data); - cachedList.emplace_back(item.first, Core::ProxyType(data)); - } - } - if (cachedList.empty() == false) { - server = _server; - server->AddRef(); - } - } - - _lock.Unlock(); - - if (server != nullptr) { - for (std::pair>& entry : cachedList) { - _server->Submit(entry.first, entry.second); - } - cachedList.clear(); - server->Release(); - } - } - - Core::ProxyType Command() { - return (Core::ProxyType(_jsonExportCommandFactory.Element())); - } - - private: - mutable Core::CriticalSection _lock; - PluginHost::IShell* _server; - ChannelMap _channels; - uint32_t _maxExportConnections; - Core::ProxyPoolType _jsonExportDataFactory; - Core::ProxyPoolType _jsonExportCommandFactory; - }; - -} // namespace Publishers -} diff --git a/MessageControl/Module.cpp b/MessageControl/Module.cpp deleted file mode 100644 index 73264e5..0000000 --- a/MessageControl/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/MessageControl/Module.h b/MessageControl/Module.h deleted file mode 100644 index 920e56d..0000000 --- a/MessageControl/Module.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_MessageControl -#endif - -#include -#include -#include - -#include -#include - - -#undef EXTERNAL -#define EXTERNAL diff --git a/Migration/CHANGELOG.md b/Migration/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/Migration/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/Migration/CMakeLists.txt b/Migration/CMakeLists.txt deleted file mode 100644 index 6760921..0000000 --- a/Migration/CMakeLists.txt +++ /dev/null @@ -1,78 +0,0 @@ - -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2025 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME Migration) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_SYSTEMMODE_AUTOSTART "false" CACHE STRING "Automatically start Migration plugin") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - Migration.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - MigrationImplementation.cpp - Module.cpp) - -include_directories( - ../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICE_L2_TEST) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/Migration/Migration.conf.in b/Migration/Migration.conf.in deleted file mode 100644 index 4be424f..0000000 --- a/Migration/Migration.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.Migration" -autostart = "false" -startuporder = "@PLUGIN_MIGRATION_STARTUPORDER@" - -configuration = JSON() -rootobject = JSON() - -rootobject.add("mode", "@PLUGIN_MIGRATION_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") - -configuration.add("root", rootobject) diff --git a/Migration/Migration.config b/Migration/Migration.config deleted file mode 100644 index 9091e66..0000000 --- a/Migration/Migration.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart false) -set (preconditions Platform) -set (callsign "org.rdk.Migration") - -if(PLUGIN_MIGRATION_STARTUPORDER) -set (startuporder ${PLUGIN_MIGRATION_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_MIGRATION_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) diff --git a/Migration/Migration.cpp b/Migration/Migration.cpp deleted file mode 100644 index 8de357a..0000000 --- a/Migration/Migration.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Migration.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 0 - - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register Migration module as wpeframework plugin - **/ - SERVICE_REGISTRATION(Migration, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - Migration::Migration() : _service(nullptr), _connectionId(0), _migration(nullptr) - { - SYSLOG(Logging::Startup, (_T("Migration Constructor"))); - } - - Migration::~Migration() - { - SYSLOG(Logging::Shutdown, (string(_T("Migration Destructor")))); - } - - const string Migration::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == _service); - ASSERT(nullptr == _migration); - ASSERT(0 == _connectionId); - - SYSLOG(Logging::Startup, (_T("Migration::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - _migration = _service->Root(_connectionId, 5000, _T("MigrationImplementation")); - - if(nullptr != _migration) - { - // Invoking Plugin API register to wpeframework - Exchange::JMigration::Register(*this, _migration); - } - else - { - SYSLOG(Logging::Startup, (_T("Migration::Initialize: Failed to initialise Migration plugin"))); - message = _T("Migration plugin could not be initialised"); - } - - return message; - } - - void Migration::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("Migration::Deinitialize")))); - - if (nullptr != _migration) - { - Exchange::JMigration::Unregister(*this); - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED uint32_t result = _migration->Release(); - - _migration = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - try - { - connection->Terminate(); - // Log success if needed - LOGWARN("Connection terminated successfully."); - } - catch (const std::exception& e) - { - std::string errorMessage = "Failed to terminate connection: "; - errorMessage += e.what(); - LOGWARN("%s",errorMessage.c_str()); - } - - connection->Release(); - } - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("Migration de-initialised")))); - } - - string Migration::Information() const - { - return string(); - } - - void Migration::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == _connectionId) { - ASSERT(nullptr != _service); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/Migration/Migration.h b/Migration/Migration.h deleted file mode 100644 index f7e4156..0000000 --- a/Migration/Migration.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" - -namespace WPEFramework -{ - namespace Plugin - { - class Migration : public PluginHost::IPlugin, public PluginHost::JSONRPC - { - public: - Migration(const Migration&) = delete; - Migration& operator=(const Migration&) = delete; - - Migration(); - virtual ~Migration(); - - BEGIN_INTERFACE_MAP(Migration) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IMigration, _migration) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* _service{}; - uint32_t _connectionId{}; - Exchange::IMigration* _migration{}; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/Migration/MigrationImplementation.cpp b/Migration/MigrationImplementation.cpp deleted file mode 100644 index 78789ae..0000000 --- a/Migration/MigrationImplementation.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "MigrationImplementation.h" - -#include -#include -#include -#include "UtilsLogging.h" -#include "UtilsgetFileContent.h" -#include "rfcapi.h" - -#define MIGRATIONSTATUS "/opt/secure/persistent/MigrationStatus" -#define TR181_MIGRATIONSTATUS "Device.DeviceInfo.Migration.MigrationStatus" - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(MigrationImplementation, 1, 0); - - MigrationImplementation::MigrationImplementation() - { - LOGINFO("MigrationImplementation Constructor called"); - } - - MigrationImplementation::~MigrationImplementation() - { - LOGINFO("MigrationImplementation Destructor called"); - } - - Core::hresult MigrationImplementation::SetMigrationStatus(const MigrationStatus status, MigrationResult& migrationResult) - { - // Map enum to string - static const std::unordered_map statusToString = { - { MIGRATION_STATUS_NOT_STARTED, "NOT_STARTED" }, - { MIGRATION_STATUS_NOT_NEEDED, "NOT_NEEDED" }, - { MIGRATION_STATUS_STARTED, "STARTED" }, - { MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED, "PRIORITY_SETTINGS_MIGRATED" }, - { MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED, "DEVICE_SETTINGS_MIGRATED" }, - { MIGRATION_STATUS_CLOUD_SETTINGS_MIGRATED, "CLOUD_SETTINGS_MIGRATED" }, - { MIGRATION_STATUS_APP_DATA_MIGRATED, "APP_DATA_MIGRATED" }, - { MIGRATION_STATUS_MIGRATION_COMPLETED, "MIGRATION_COMPLETED" } - }; - - auto it = statusToString.find(status); - if (it != statusToString.end()) { - // if file exists, it will be truncated, otherwise it will be created - std::ofstream file(MIGRATIONSTATUS, std::ios::trunc); - if (file.is_open()) { - // Write the string status to the file - file << it->second; - LOGINFO("Current ENTOS Migration Status is %s\n", it->second.c_str()); - } else { - LOGERR("Failed to open or create file %s\n", MIGRATIONSTATUS); - return (ERROR_FILE_IO); - } - file.close(); - } else { - LOGERR("Invalid Migration Status\n"); - return (WPEFramework::Core::ERROR_INVALID_PARAMETER); - } - migrationResult.success = true; - return WPEFramework::Core::ERROR_NONE; - } - - Core::hresult MigrationImplementation::GetMigrationStatus(MigrationStatusInfo& migrationStatusInfo) - { - bool status = false; - RFC_ParamData_t param = {0}; - WDMP_STATUS wdmpstatus = getRFCParameter((char*)"thunderapi", TR181_MIGRATIONSTATUS, ¶m); - if (WDMP_SUCCESS == wdmpstatus) { - std::string migrationStatusStr = param.value; - - static const std::unordered_map stringToStatus = { - {"NOT_STARTED", MIGRATION_STATUS_NOT_STARTED}, - {"NOT_NEEDED", MIGRATION_STATUS_NOT_NEEDED}, - {"STARTED", MIGRATION_STATUS_STARTED}, - {"PRIORITY_SETTINGS_MIGRATED", MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED}, - {"DEVICE_SETTINGS_MIGRATED", MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED}, - {"CLOUD_SETTINGS_MIGRATED", MIGRATION_STATUS_CLOUD_SETTINGS_MIGRATED}, - {"APP_DATA_MIGRATED", MIGRATION_STATUS_APP_DATA_MIGRATED}, - {"MIGRATION_COMPLETED", MIGRATION_STATUS_MIGRATION_COMPLETED} - }; - - auto it = stringToStatus.find(migrationStatusStr); - if (it != stringToStatus.end()) { - migrationStatusInfo.migrationStatus = it->second; - LOGINFO("Current ENTOS Migration Status is: %s\n", migrationStatusStr.c_str()); - status = true; - } - } else { - LOGINFO("Failed to get RFC parameter for Migration Status \n"); - } - - return (status ? static_cast(WPEFramework::Core::ERROR_NONE) : static_cast(ERROR_FILE_IO)); - } - - Core::hresult MigrationImplementation::GetBootTypeInfo(BootTypeInfo& bootTypeInfo) - { - bool status = false; - const char* filename = "/tmp/bootType"; - std::string propertyName = "BOOT_TYPE"; - std::string bootTypeStr; - - if (Utils::readPropertyFromFile(filename, propertyName, bootTypeStr)) { - static const std::unordered_map stringToBootType = { - {"BOOT_INIT", BOOT_TYPE_INIT}, - {"BOOT_NORMAL", BOOT_TYPE_NORMAL}, - {"BOOT_MIGRATION", BOOT_TYPE_MIGRATION}, - {"BOOT_UPDATE", BOOT_TYPE_UPDATE} - }; - - auto it = stringToBootType.find(bootTypeStr); - if (it != stringToBootType.end()) { - bootTypeInfo.bootType = it->second; - LOGINFO("Boot type changed to: %s, current OS Class: rdke\n", bootTypeStr.c_str()); - status = true; - } - } else { - LOGERR("BootType is not present"); - } - return (status ? static_cast(WPEFramework::Core::ERROR_NONE) : static_cast(ERROR_FILE_IO)); - } - } // namespace Plugin -} // namespace WPEFramework diff --git a/Migration/MigrationImplementation.h b/Migration/MigrationImplementation.h deleted file mode 100644 index 2f244f4..0000000 --- a/Migration/MigrationImplementation.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include - -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - class MigrationImplementation : public Exchange::IMigration - { - public: - // We do not allow this plugin to be copied !! - MigrationImplementation(); - ~MigrationImplementation() override; - - // We do not allow this plugin to be copied !! - MigrationImplementation(const MigrationImplementation&) = delete; - MigrationImplementation& operator=(const MigrationImplementation&) = delete; - - BEGIN_INTERFACE_MAP(MigrationImplementation) - INTERFACE_ENTRY(Exchange::IMigration) - END_INTERFACE_MAP - - public: - Core::hresult GetBootTypeInfo(BootTypeInfo& bootTypeInfo) override; - Core::hresult SetMigrationStatus(const MigrationStatus status, MigrationResult& migrationResult) override; - Core::hresult GetMigrationStatus(MigrationStatusInfo& migrationStatusInfo) override; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/Migration/Module.cpp b/Migration/Module.cpp deleted file mode 100644 index 7849dfd..0000000 --- a/Migration/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Migration/Module.h b/Migration/Module.h deleted file mode 100644 index 797e8a6..0000000 --- a/Migration/Module.h +++ /dev/null @@ -1,30 +0,0 @@ - -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_Migration -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/Migration/README.md b/Migration/README.md deleted file mode 100644 index 9deb648..0000000 --- a/Migration/README.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------ -# Migration - -## Callsign -`org.rdk.Migration` - -## Methods: -``` -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc": "2.0","id":3,"method": "Controller.1.activate","params": {"callsign": "org.rdk.Migration"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.Migration.getBootTypeInfo"}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.Migration.getMigrationStatus"}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.Migration.setMigrationStatus","params":{"status": NOT_STARTED}}' http://127.0.0.1:9998/jsonrpc -``` - -## Responses -``` -getBootTypeInfo: -{"jsonrpc":"2.0","id":3,"result":{"bootType":"BOOT_NORMAL"}} - -getMigrationStatus: -{"jsonrpc":"2.0","id":3,"result":{"migrationStatus":"NOT_NEEDED"}} - -setMigrationStatus: -{"jsonrpc":"2.0","id":3,"result":{"success":true}} -``` - -## Events -``` -none -``` diff --git a/Monitor/.gitignore b/Monitor/.gitignore deleted file mode 100644 index 8b13789..0000000 --- a/Monitor/.gitignore +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Monitor/CHANGELOG.md b/Monitor/CHANGELOG.md deleted file mode 100644 index bd0f9dd..0000000 --- a/Monitor/CHANGELOG.md +++ /dev/null @@ -1,23 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - -## [1.1.0] - 2025-03-25 -### Fixed -- Sync up Monitor Plugin with RDKV (rdkcentral/rdkservices) - -## [1.0.0] - 2022-05-11 -### Added -- Add CHANGELOG diff --git a/Monitor/CMakeLists.txt b/Monitor/CMakeLists.txt deleted file mode 100644 index d8e4234..0000000 --- a/Monitor/CMakeLists.txt +++ /dev/null @@ -1,96 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(Monitor) - -cmake_minimum_required(VERSION 3.3) - -find_package(WPEFramework) - -set(PLUGIN_NAME Monitor) -set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) - -set(PLUGIN_MONITOR_AUTOSTART "true" CACHE STRING "Automatically start Monitor plugin") -set(PLUGIN_MONITOR_STARTUPORDER "" CACHE STRING "Automatically start Monitor plugin") -# Plugins built from this repository that can be autmatically enabled or enabled manually when built externally -set(PLUGIN_MONITOR_OPENCDMI "${PLUGIN_OPENCDMI}" CACHE BOOL "Enable monitor for the OpenCDMI plugin") -set(PLUGIN_MONITOR_WEBKITBROWSER "${PLUGIN_WEBKITBROWSER}" CACHE BOOL "Enable monitor for the WebKitBrowser plugin") -set(PLUGIN_MONITOR_WEBKITBROWSER_APPS "${PLUGIN_WEBKITBROWSER_APPS}" CACHE BOOL "Enable monitor for the WebKitBrowser Apps plugin") -set(PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP "${PLUGIN_WEBKITBROWSER_RESIDENT_APP}" CACHE BOOL "Enable monitor for the WebKitBrowser Resident App plugin") -set(PLUGIN_MONITOR_WEBKITBROWSER_UX "${PLUGIN_WEBKITBROWSER_UX}" CACHE BOOL "Enable monitor for the WebKitBrowser UX plugin") -set(PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE "${PLUGIN_WEBKITBROWSER_YOUTUBE}" CACHE BOOL "Enable monitor for the WebKitBrowser Youtube plugin") -set(PLUGIN_MONITOR_SYSTEMAUDIOPLAYER "${PLUGIN_SYSTEMAUDIOPLAYER}" CACHE BOOL "Enable monitor for the SystemAudioPlayer plugin") -# By Default NetworkManager plugin Monitor is in ON state -set(PLUGIN_MONITOR_NETWORKMANAGER ON) - -# Plugins built from outside of this repository have to be enabled manually -set(PLUGIN_MONITOR_AMAZON OFF CACHE BOOL "Enable monitor for the Amazon plugin") -set(PLUGIN_MONITOR_COBALT OFF CACHE BOOL "Enable monitor for the Cobalt plugin") -set(PLUGIN_MONITOR_NETFLIX OFF CACHE BOOL "Enable monitor for the Netflix plugin") -set(PLUGIN_MONITOR_OUTOFPROCESS OFF CACHE BOOL "Enable monitor for the OutOfProcess plugin") -set(PLUGIN_MONITOR_TESTUTILITY OFF CACHE BOOL "Enable monitor for the TestUtility plugin") - -# Options for each plugin -set(PLUGIN_MONITOR_AMAZON_MEMORYLIMIT "614400" CACHE STRING "monitor amazon memory limit") -set(PLUGIN_MONITOR_COBALT_MEMORYLIMIT "614400" CACHE STRING "monitor cobalt memory limit") -set(PLUGIN_MONITOR_NETFLIX_MEMORYLIMIT "614400" CACHE STRING "monitor netflix memory limit") -set(PLUGIN_MONITOR_WEBKITBROWSER_MEMORYLIMIT "614400" CACHE STRING "monitor webkit memory limit") -set(PLUGIN_MONITOR_WEBKITBROWSER_APPS_MEMORYLIMIT "614400" CACHE STRING "monitor apps memory limit") -set(PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP_MEMORYLIMIT "614400" CACHE STRING "monitor resident app memory limit") -set(PLUGIN_MONITOR_WEBKITBROWSER_UX_MEMORYLIMIT "614400" CACHE STRING "monitor ux memory limit") -set(PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE_MEMORYLIMIT "614400" CACHE STRING "monitor youtube memory limit") -set(PLUGIN_MONITOR_NETWORKMANAGER_MEMORYLIMIT "614400" CACHE STRING "monitor networkmanager memory limit") - -# deprecated/legacy flags support -if(PLUGIN_MONITOR_APPS_MEMORYLIMIT) - set(PLUGIN_MONITOR_WEBKITBROWSER_APPS_MEMORYLIMIT ${PLUGIN_MONITOR_APPS_MEMORYLIMIT} CACHE STRING "monitor apps memory limit" FORCE) - unset(PLUGIN_MONITOR_APPS_MEMORYLIMIT CACHE) -endif() -if(PLUGIN_MONITOR_RESIDENT_APP_MEMORYLIMIT) - set(PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP_MEMORYLIMIT ${PLUGIN_MONITOR_RESIDENT_APP_MEMORYLIMIT} CACHE STRING "monitor resident app memory limit" FORCE) - unset(PLUGIN_MONITOR_RESIDENT_APP_MEMORYLIMIT CACHE) -endif() -if(PLUGIN_MONITOR_UX_MEMORYLIMIT) - set(PLUGIN_MONITOR_WEBKITBROWSER_UX_MEMORYLIMIT ${PLUGIN_MONITOR_UX_MEMORYLIMIT} CACHE STRING "monitor ux memory limit" FORCE) - unset(PLUGIN_MONITOR_UX_MEMORYLIMIT CACHE) -endif() -if(PLUGIN_MONITOR_YOUTUBE_MEMORYLIMIT) - set(PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE_MEMORYLIMIT ${PLUGIN_MONITOR_YOUTUBE_MEMORYLIMIT} CACHE STRING "monitor youtube memory limit" FORCE) - unset(PLUGIN_MONITOR_YOUTUBE_MEMORYLIMIT CACHE) -endif() - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - Monitor.cpp - MonitorJsonRpc.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PROJECT_NAME}) diff --git a/Monitor/Module.cpp b/Monitor/Module.cpp deleted file mode 100644 index a85f162..0000000 --- a/Monitor/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Monitor/Module.h b/Monitor/Module.h deleted file mode 100644 index ebd9f99..0000000 --- a/Monitor/Module.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __MODULE_PLUGIN_MONITOR_H -#define __MODULE_PLUGIN_MONITOR_H - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_Monitor -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL - -#endif // __MODULE_PLUGIN_MONITOR_H diff --git a/Monitor/Monitor.conf.in b/Monitor/Monitor.conf.in deleted file mode 100644 index 2e4b3a6..0000000 --- a/Monitor/Monitor.conf.in +++ /dev/null @@ -1,217 +0,0 @@ -autostart = "@PLUGIN_MONITOR_AUTOSTART@" -startuporder = "@PLUGIN_MONITOR_STARTUPORDER@" - -configuration = JSON() - -observable_list = [] - -if boolean("@PLUGIN_MONITOR_WEBKITBROWSER@"): - observable_config = JSON() - observable_config.add("callsign", "WebKitBrowser") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_WEBKITBROWSER_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE@"): - observable_config = JSON() - observable_config.add("callsign", "YouTube") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_AMAZON@"): - observable_config = JSON() - observable_config.add("callsign", "Amazon") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_AMAZON_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_COBALT@"): - observable_config = JSON() - observable_config.add("callsign", "Cobalt") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_COBALT_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_WEBKITBROWSER_APPS@"): - observable_config = JSON() - observable_config.add("callsign", "Apps") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_WEBKITBROWSER_APPS_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_WEBKITBROWSER_UX@"): - observable_config = JSON() - observable_config.add("callsign", "UX") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_WEBKITBROWSER_UX_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_NETFLIX@"): - observable_config = JSON() - observable_config.add("callsign", "Netflix") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_NETFLIX_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_OUTOFPROCESS@"): - observable_config = JSON() - observable_config.add("callsign", "OutOfProcessPlugin") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "3000") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_TESTUTILITY@"): - observable_config = JSON() - observable_config.add("callsign", "TestUtility") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "3000") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_OPENCDMI@"): - observable_config = JSON() - observable_config.add("callsign", "OCDM") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_TEXTTOSPEECH@"): - observable_config = JSON() - observable_config.add("callsign", "org.rdk.TextToSpeech") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_SYSTEMAUDIOPLAYER@"): - observable_config = JSON() - observable_config.add("callsign", "org.rdk.SystemAudioPlayer") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP@"): - observable_config = JSON() - observable_config.add("callsign", "ResidentApp") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "3") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_NETWORKMANAGER@"): - observable_config = JSON() - observable_config.add("callsign", "org.rdk.NetworkManager") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_NETWORKMANAGER_MEMORYLIMIT@") - observable_config.add("operational", "1") - restart_config = JSON() - restart_config.add("window", "60") - restart_config.add("limit", "60") - observable_config.add("restart", restart_config) - observable_list.append(observable_config) - -if boolean("@PLUGIN_MONITOR_CLONED_APPS@"): - observable_config = JSON() - observable_config.add("callsign", "SearchAndDiscovery") - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_SEARCH_AND_DISCOVERY_MEMORYLIMIT@") - observable_list.append(observable_config) - - for N in range(4): - #name = "HtmlApp-" + str(N) - observable_config = JSON() - observable_config.add("callsign", "HtmlApp-" + str(N)) - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT@") - observable_list.append(observable_config) - - for N in range(4): - observable_config = JSON() - observable_config.add("callsign", "LightningApp-" + str(N)) - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT@") - observable_list.append(observable_config) - - observable_config = JSON() - observable_config.add("callsign", "Cobalt-0") - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT@") - observable_list.append(observable_config) - - observable_config = JSON() - observable_config.add("callsign", "Netflix-0") - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_NETFLIX_APP_MEMORYLIMIT@") - observable_list.append(observable_config) - - observable_config = JSON() - observable_config.add("callsign", "JSPP") - observable_config.add("operational", "-1") - observable_config.add("memory", "5") - observable_config.add("memorylimit", "@PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT@") - observable_list.append(observable_config) - -configuration.add("observables", observable_list) - diff --git a/Monitor/Monitor.config b/Monitor/Monitor.config deleted file mode 100644 index 88f1fc9..0000000 --- a/Monitor/Monitor.config +++ /dev/null @@ -1,291 +0,0 @@ -set(autostart ${PLUGIN_MONITOR_AUTOSTART}) - -if(PLUGIN_MONITOR_STARTUPORDER) -set (startuporder ${PLUGIN_MONITOR_STARTUPORDER}) -endif() - -map() -end() -ans(configuration) - -if(PLUGIN_MONITOR_WEBKITBROWSER) - map() - kv(callsign WebKitBrowser) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_WEBKITBROWSER_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(WEBKITBROWSER_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${WEBKITBROWSER_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE) - map() - kv(callsign YouTube) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_WEBKITBROWSER_YOUTUBE_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(YOUTUBE_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${YOUTUBE_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_AMAZON) - map() - kv(callsign Amazon) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_AMAZON_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(AMAZON_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${AMAZON_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_COBALT) - map() - kv(callsign Cobalt) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_COBALT_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(COBALT_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${COBALT_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_WEBKITBROWSER_APPS) - map() - kv(callsign Apps) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_WEBKITBROWSER_APPS_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(APPS_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${APPS_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_WEBKITBROWSER_UX) - map() - kv(callsign UX) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_WEBKITBROWSER_UX_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(UX_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${UX_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_NETFLIX) - map() - kv(callsign Netflix) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_NETFLIX_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(NETFLIX_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${NETFLIX_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_OUTOFPROCESS) - map() - kv(callsign OutOfProcessPlugin) - kv(memory 5) - kv(memorylimit 3000) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(OUTOFPROCESSTEST_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${OUTOFPROCESSTEST_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_TESTUTILITY) - map() - kv(callsign TestUtility) - kv(memory 5) - kv(memorylimit 3000) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(TESTUTILITY_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${TESTUTILITY_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_OPENCDMI) - map() - kv(callsign OCDM) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(OPENCDMI_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${OPENCDMI_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_TEXTTOSPEECH) - map() - kv(callsign org.rdk.TextToSpeech) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(TEXTTOSPEECH_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${TEXTTOSPEECH_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_SYSTEMAUDIOPLAYER) - map() - kv(callsign org.rdk.SystemAudioPlayer) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(SYSTEMAUDIOPLAYER_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${SYSTEMAUDIOPLAYER_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP) - map() - kv(callsign ResidentApp) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 3) - end() - end() - ans(RESIDENT_APP_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${RESIDENT_APP_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_NETWORKMANAGER) - map() - kv(callsign org.rdk.NetworkManager) - kv(memory 5) - kv(memorylimit ${PLUGIN_MONITOR_NETWORKMANAGER_MEMORYLIMIT}) - kv(operational 1) - key(restart) - map() - kv(window 60) - kv(limit 60) - end() - end() - ans(NETWORK_MANAGER_MONITOR_CONFIG) - map_append(${configuration} observables ___array___) - map_append(${configuration} observables ${NETWORK_MANAGER_MONITOR_CONFIG}) -endif() - -if(PLUGIN_MONITOR_INSTANCES_LIST) - - # 'PLUGIN_MONITOR_INSTANCES_LIST' contains a semi-colon (';') separated list of Monitor observable - # instances. In turn, each instance is a comma (',') separated list defining an observable instance - # element ("callsign,memory,memorylimit,operational,window,limit"), where: - # - "callsign": The callsign/name of the plugin to be monitored. - # - "memory": Interval in seconds used for checking the plugin's memory usage. - # If 0, means don't check memory. - # - "memorylimit": Value in KiB above which memory usage is considered excessive. - # Ignored if "memory" is zero. - # - "operational": Interval in seconds used for checking plugin's operational state. - # - "window": Interval in seconds considered for callsign restart throttling. - # - "limit": Maximum number of times the plugin can be restarted within the "window" time. - # More details of the parameters is available at https://github.com/rdkcentral/rdkservices/tree/sprint/2101/Monitor/doc - - map_append(${configuration} observables ___array___) - foreach(instance ${PLUGIN_MONITOR_INSTANCES_LIST}) - string(REPLACE "," ";" instance_conf ${instance}) - - set(instance_conf_list_required_length 6) - list(LENGTH instance_conf instance_conf_list_length) - if (NOT instance_conf_list_length EQUAL instance_conf_list_required_length) - message(FATAL_ERROR "Instance conf '${instance}': Must have ${instance_conf_list_required_length} entries 'callsign,memory,memorylimit,operational,window,limit', but only has ${instance_conf_list_length} entries") - endif() - - list(GET instance_conf 0 name) - list(GET instance_conf 1 memory) - list(GET instance_conf 2 memorylimit) - list(GET instance_conf 3 operational) - list(GET instance_conf 4 window) - list(GET instance_conf 5 limit) - - map() - kv(callsign ${name}) - if(NOT "${memory}" STREQUAL "0") - kv(memory ${memory}) - kv(memorylimit ${memorylimit}) - endif() - kv(operational ${operational}) - key(restart) - map() - kv(window ${window}) - kv(limit ${limit}) - end() - end() - ans(monitor_conf) - map_append(${configuration} observables ${monitor_conf}) - endforeach() -endif() diff --git a/Monitor/Monitor.cpp b/Monitor/Monitor.cpp deleted file mode 100644 index 339491f..0000000 --- a/Monitor/Monitor.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Monitor.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 1 -#define API_VERSION_NUMBER_PATCH 0 - -namespace WPEFramework { -namespace Plugin { - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - static Core::ProxyPoolType>> jsonBodyDataFactory(2); - static Core::ProxyPoolType> jsonBodyParamFactory(2); - static Core::ProxyPoolType> jsonMemoryBodyDataFactory(2); - - /* virtual */ const string Monitor::Initialize(PluginHost::IShell* service) - { - - _config.FromString(service->ConfigLine()); - - _skipURL = static_cast(service->WebPrefix().length()); - - Core::JSON::ArrayType::Iterator index(_config.Observables.Elements()); - - // Create a list of plugins to monitor.. - _monitor.Open(service, index); - - // During the registartion, all Plugins, currently active are reported to the sink. - service->Register(&_monitor); - - RegisterAll(); - - // On succes return a name as a Callsign to be used in the URL, after the "service"prefix - return (_T("")); - } - - /* virtual */ void Monitor::Deinitialize(PluginHost::IShell* service) - { - UnregisterAll(); - - service->Unregister(&_monitor); - - _monitor.Close(); - } - - /* virtual */ string Monitor::Information() const - { - // No additional info to report. - return (nullptr); - } - - /* virtual */ void Monitor::Inbound(Web::Request& request) - { - if ((request.Verb == Web::Request::HTTP_PUT) || (request.Verb == Web::Request::HTTP_POST)) - request.Body(jsonBodyParamFactory.Element()); - } - - // ../ Get all Memory Measurments - // ../ Get the Memory Measurements for Callsign - // ../ Reset the Memory measurements for Callsign - /* virtual */ Core::ProxyType Monitor::Process(const Web::Request& request) - { - ASSERT(_skipURL <= request.Path.length()); - - Core::ProxyType result(PluginHost::IFactories::Instance().Response()); - Core::TextSegmentIterator index(Core::TextFragment(request.Path, _skipURL, static_cast(request.Path.length() - _skipURL)), false, '/'); - - // If there is an entry, the first one will alwys be a '/', skip this one.. - index.Next(); - - // By default, we assume everything works.. - result->ErrorCode = Web::STATUS_OK; - result->Message = "OK"; - - if (request.Verb == Web::Request::HTTP_GET) { - // Let's list them all.... - if (index.Next() == false) { - if (_monitor.Length() > 0) { - Core::ProxyType>> response(jsonBodyDataFactory.Element()); - - _monitor.Snapshot(*response); - - result->Body(Core::ProxyType(response)); - } - } else { - MetaData memoryInfo; - bool operational = false; - - // Seems we only want 1 name - if (_monitor.Snapshot(index.Current().Text(), memoryInfo, operational) == true) { - Core::ProxyType> response(jsonMemoryBodyDataFactory.Element()); - - *response = Monitor::Data::MetaData(memoryInfo, operational); - - result->Body(Core::ProxyType(response)); - } - } - - result->ContentType = Web::MIME_JSON; - } else if ((request.Verb == Web::Request::HTTP_PUT) && (index.Next() == true)) { - MetaData memoryInfo; - bool operational = false; - - // Seems we only want 1 name - if (_monitor.Reset(index.Current().Text(), memoryInfo, operational) == true) { - Core::ProxyType> response(jsonMemoryBodyDataFactory.Element()); - - *response = Monitor::Data::MetaData(memoryInfo, operational); - - result->Body(Core::ProxyType(response)); - } - - result->ContentType = Web::MIME_JSON; - } else if ((request.Verb == Web::Request::HTTP_POST) && (request.HasBody())) { - Core::ProxyType body(request.Body()); - string observable = body->Observable.Value(); - - uint16_t restartWindow = 0; - uint8_t restartLimit = 0; - - if (body->Restart.IsSet()) { - restartWindow = body->Restart.Window; - restartLimit = body->Restart.Limit; - } - TRACE(Trace::Information, (_T("Sets Restart Limits:[LIMIT:%d, WINDOW:%d]"), restartLimit, restartWindow)); - _monitor.Update(observable, restartWindow, restartLimit); - } else { - result->ErrorCode = Web::STATUS_BAD_REQUEST; - result->Message = _T(" could not handle your request."); - } - - return (result); - } -} -} diff --git a/Monitor/Monitor.h b/Monitor/Monitor.h deleted file mode 100644 index 9b63ee8..0000000 --- a/Monitor/Monitor.h +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __MONITOR_H -#define __MONITOR_H - -#include "Module.h" -#include -#include -#include -#include - -static uint32_t gcd(uint32_t a, uint32_t b) -{ - return b == 0 ? a : gcd(b, a % b); -} - -namespace WPEFramework { -namespace Plugin { - - class Monitor : public PluginHost::IPlugin, public PluginHost::IWeb, public PluginHost::JSONRPC { - private: - class RestartInfo : public Core::JSON::Container { - public: - RestartInfo& operator=(const RestartInfo&) = delete; - - RestartInfo() - : Core::JSON::Container() - { - Add(_T("window"), &Window); - Add(_T("limit"), &Limit); - } - RestartInfo(const RestartInfo& copy) - : Core::JSON::Container() - , Window(copy.Window) - , Limit(copy.Limit) - { - Add(_T("window"), &Window); - Add(_T("limit"), &Limit); - } - virtual ~RestartInfo() - { - } - - Core::JSON::DecUInt16 Window; - Core::JSON::DecUInt8 Limit; - }; - - public: - class MetaData { - public: - MetaData() - : _resident() - , _allocated() - , _shared() - , _process() - { - } - MetaData(const MetaData& copy) - : _resident(copy._resident) - , _allocated(copy._allocated) - , _shared(copy._shared) - , _process(copy._process) - { - } - ~MetaData() - { - } - - MetaData& operator= (const MetaData& rhs) - { - _resident = rhs._resident; - _allocated = rhs._allocated; - _shared = rhs._shared; - _process = rhs._process; - - return (*this); - } - - public: - bool HasMeasurements() const { - return ((_resident.Measurements() != 0) || (_allocated.Measurements() != 0) || (_shared.Measurements() != 0) || (_process.Measurements() != 0)); - } - - void AddMeasurements(const uint64_t resident, const uint64_t allocated, const uint64_t shared, const uint64_t process) { - _resident.Set(resident); - _allocated.Set(allocated); - _shared.Set(shared); - _process.Set(process); - } - - void Measure(Exchange::IMemory* memInterface) - { - _resident.Set(memInterface->Resident()); - _allocated.Set(memInterface->Allocated()); - _shared.Set(memInterface->Shared()); - _process.Set(memInterface->Processes()); - } - void Reset() - { - _resident.Reset(); - _allocated.Reset(); - _shared.Reset(); - _process.Reset(); - } - - public: - inline const Core::MeasurementType& Resident() const - { - return (_resident); - } - inline const Core::MeasurementType& Allocated() const - { - return (_allocated); - } - inline const Core::MeasurementType& Shared() const - { - return (_shared); - } - inline const Core::MeasurementType& Process() const - { - return (_process); - } - private: - Core::MeasurementType _resident; - Core::MeasurementType _allocated; - Core::MeasurementType _shared; - Core::MeasurementType _process; - }; - - class Data : public Core::JSON::Container { - public: - class MetaData : public Core::JSON::Container { - public: - class Measurement : public Core::JSON::Container { - public: - Measurement() - : Core::JSON::Container() - { - Add(_T("min"), &Min); - Add(_T("max"), &Max); - Add(_T("average"), &Average); - Add(_T("last"), &Last); - } - Measurement(const uint64_t min, const uint64_t max, const uint64_t average, const uint64_t last) - : Core::JSON::Container() - { - Add(_T("min"), &Min); - Add(_T("max"), &Max); - Add(_T("average"), &Average); - Add(_T("last"), &Last); - - Min = min; - Max = max; - Average = average; - Last = last; - } - Measurement(const Core::MeasurementType& input) - : Core::JSON::Container() - { - Add(_T("min"), &Min); - Add(_T("max"), &Max); - Add(_T("average"), &Average); - Add(_T("last"), &Last); - - Min = input.Min(); - Max = input.Max(); - Average = input.Average(); - Last = input.Last(); - } - Measurement(const Core::MeasurementType& input) - : Core::JSON::Container() - { - Add(_T("min"), &Min); - Add(_T("max"), &Max); - Add(_T("average"), &Average); - Add(_T("last"), &Last); - - Min = input.Min(); - Max = input.Max(); - Average = input.Average(); - Last = input.Last(); - } - Measurement(const Measurement& copy) - : Core::JSON::Container() - , Min(copy.Min) - , Max(copy.Max) - , Average(copy.Average) - , Last(copy.Last) - { - Add(_T("min"), &Min); - Add(_T("max"), &Max); - Add(_T("average"), &Average); - Add(_T("last"), &Last); - } - ~Measurement() - { - } - - public: - Measurement& operator=(const Measurement& RHS) - { - Min = RHS.Min; - Max = RHS.Max; - Average = RHS.Average; - Last = RHS.Last; - - return (*this); - } - Measurement& operator=(const Core::MeasurementType& RHS) - { - Min = RHS.Min(); - Max = RHS.Max(); - Average = RHS.Average(); - Last = RHS.Last(); - - return (*this); - } - - public: - Core::JSON::DecUInt64 Min; - Core::JSON::DecUInt64 Max; - Core::JSON::DecUInt64 Average; - Core::JSON::DecUInt64 Last; - }; - - public: - MetaData() - : Core::JSON::Container() - , Allocated() - , Resident() - , Shared() - , Process() - , Operational() - , Count() - { - Add(_T("allocated"), &Allocated); - Add(_T("resident"), &Resident); - Add(_T("shared"), &Shared); - Add(_T("process"), &Process); - Add(_T("operational"), &Operational); - Add(_T("count"), &Count); - } - MetaData(const Monitor::MetaData& input, const bool operational) - : Core::JSON::Container() - { - Add(_T("allocated"), &Allocated); - Add(_T("resident"), &Resident); - Add(_T("shared"), &Shared); - Add(_T("process"), &Process); - Add(_T("operational"), &Operational); - Add(_T("count"), &Count); - - Allocated = input.Allocated(); - Resident = input.Resident(); - Shared = input.Shared(); - Process = input.Process(); - Operational = operational; - Count = input.Allocated().Measurements(); - } - MetaData(const MetaData& copy) - : Core::JSON::Container() - , Allocated(copy.Allocated) - , Resident(copy.Resident) - , Shared(copy.Shared) - , Process(copy.Process) - , Operational(copy.Operational) - , Count(copy.Count) - { - Add(_T("allocated"), &Allocated); - Add(_T("resident"), &Resident); - Add(_T("shared"), &Shared); - Add(_T("process"), &Process); - Add(_T("operational"), &Operational); - Add(_T("count"), &Count); - } - ~MetaData() - { - } - - MetaData& operator=(const MetaData& RHS) - { - Allocated = RHS.Allocated; - Resident = RHS.Resident; - Shared = RHS.Shared; - Process = RHS.Process; - Operational = RHS.Operational; - Count = RHS.Count; - - return (*this); - } - - public: - Measurement Allocated; - Measurement Resident; - Measurement Shared; - Measurement Process; - Core::JSON::Boolean Operational; - Core::JSON::DecUInt32 Count; - }; - - private: - Data& operator=(const Data&); - - public: - Data() - : Core::JSON::Container() - , Name() - , Measurement() - , Observable() - , Restart() - { - Add(_T("name"), &Name); - Add(_T("measurment"), &Measurement); - Add(_T("observable"), &Observable); - Add(_T("restart"), &Restart); - } - Data(const string& name, const Monitor::MetaData& info, const bool operational) - : Core::JSON::Container() - , Name() - , Measurement(info, operational) - , Observable() - , Restart() - { - Add(_T("name"), &Name); - Add(_T("measurment"), &Measurement); - Add(_T("observable"), &Observable); - Add(_T("restart"), &Restart); - - Name = name; - } - Data(const Data& copy) - : Core::JSON::Container() - , Name(copy.Name) - , Measurement(copy.Measurement) - , Observable(copy.Observable) - , Restart(copy.Restart) - { - Add(_T("name"), &Name); - Add(_T("measurment"), &Measurement); - Add(_T("observable"), &Observable); - Add(_T("restart"), &Restart); - } - ~Data() - { - } - - public: - Core::JSON::String Name; - MetaData Measurement; - Core::JSON::String Observable; - RestartInfo Restart; - }; - - private: - Monitor(const Monitor&); - Monitor& operator=(const Monitor&); - - class Config : public Core::JSON::Container { - private: - Config(const Config&); - Config& operator=(const Config&); - - public: - class Entry : public Core::JSON::Container { - private: - Entry& operator=(const Entry& RHS); - - public: - Entry() - : Core::JSON::Container() - { - Add(_T("callsign"), &Callsign); - Add(_T("memory"), &MetaData); - Add(_T("memorylimit"), &MetaDataLimit); - Add(_T("operational"), &Operational); - Add(_T("restart"), &Restart); - } - Entry(const Entry& copy) - : Core::JSON::Container() - , Callsign(copy.Callsign) - , MetaData(copy.MetaData) - , MetaDataLimit(copy.MetaDataLimit) - , Operational(copy.Operational) - , Restart(copy.Restart) - { - Add(_T("callsign"), &Callsign); - Add(_T("memory"), &MetaData); - Add(_T("memorylimit"), &MetaDataLimit); - Add(_T("operational"), &Operational); - Add(_T("restart"), &Restart); - } - ~Entry() - { - } - - public: - Core::JSON::String Callsign; - Core::JSON::DecUInt32 MetaData; - Core::JSON::DecUInt32 MetaDataLimit; - Core::JSON::DecSInt32 Operational; - RestartInfo Restart; - }; - - public: - Config() - : Core::JSON::Container() - { - Add(_T("observables"), &Observables); - } - ~Config() - { - } - - public: - Core::JSON::ArrayType Observables; - }; - - class MonitorObjects : public PluginHost::IPlugin::INotification, public PluginHost::IPlugin::ILifeTime { - public: - using Job = Core::ThreadPool::JobType; - - class MonitorObject { - public: - MonitorObject() = delete; - MonitorObject& operator=(const MonitorObject&) = delete; - - enum evaluation { - SUCCESFULL = 0x00, - NOT_OPERATIONAL = 0x01, - EXCEEDED_MEMORY = 0x02 - }; - - typedef struct { - int32_t Limit; - int32_t WindowSeconds; - } RestartSettings; - - public: - MonitorObject( - const bool actOnOperational, - const uint32_t operationalInterval, - const uint32_t memoryInterval, - const uint64_t memoryThreshold, - const uint64_t absTime, - const uint16_t restartWindow, - const uint8_t restartLimit) - : _operationalInterval(operationalInterval) - , _memoryInterval(memoryInterval) - , _memoryThreshold(memoryThreshold * 1024) - , _operationalSlots(operationalInterval) - , _memorySlots(memoryInterval) - , _nextSlot(absTime) - , _restartWindow(restartWindow) - , _restartWindowStart() - , _restartCount(0) - , _restartLimit(restartLimit) - , _measurement() - , _operational(false) - , _operationalEvaluate(actOnOperational) - , _source(nullptr) - , _interval( ((operationalInterval != 0) || (_memoryInterval != 0)) ? gcd(_operationalInterval, _memoryInterval) : 0 ) - , _active{ false } - , _adminLock() - { - ASSERT((_operationalInterval != 0) || (_memoryInterval != 0)); - } - ~MonitorObject() - { - if (_source != nullptr) { - _source->Release(); - _source = nullptr; - } - } - - MonitorObject(MonitorObject&) = delete; - MonitorObject& operator=(MonitorObject&) = delete; - MonitorObject(MonitorObject&&) = delete; - MonitorObject& operator=(MonitorObject&&) = delete; - - public: - inline bool RegisterRestart(PluginHost::IShell::reason why VARIABLE_IS_NOT_USED) - { - ASSERT(why == PluginHost::IShell::MEMORY_EXCEEDED || why == PluginHost::IShell::FAILURE); - ASSERT(HasRestartAllowed()); - - if (((_restartWindowStart.IsValid() == true) && (_restartWindowStart > Core::Time::Now())) || (_restartWindow == 0)) { - // It's within window. - _restartCount += _restartCount + 1; - } else { - _restartWindowStart = Core::Time::Now().Add(_restartWindow * 1000 /* ms */); - _restartCount = 0; - } - - bool result = ((_restartLimit == 0) || (_restartCount < _restartLimit)); - if (result == false) { - _restartCount = 0; - } - - return result; - } - inline uint8_t RestartLimit() const - { - return _restartLimit; - } - inline uint16_t RestartWindow() const - { - return _restartWindow; - } - inline void UpdateRestartLimits( - const uint16_t restartWindow, - const uint8_t restartLimit) - { - _restartWindow = restartWindow; - _restartLimit = restartLimit; - } - inline bool HasRestartAllowed() const - { - return (_operationalEvaluate); - } - inline uint32_t Interval() const - { - return (_interval); - } - inline uint32_t Operational() const - { - return (_operational); - } - inline const MetaData& Measurement() const - { - Core::SafeSyncType guard(_adminLock); - return (_measurement); - } - inline uint64_t TimeSlot() const - { - return (_nextSlot); - } - inline void Reset() - { - Core::SafeSyncType guard(_adminLock); - _measurement.Reset(); - } - inline void Retrigger(uint64_t currentSlot) - { - while (_nextSlot < currentSlot) { - _nextSlot += _interval; - } - } - inline void Set(Exchange::IMemory* memory) - { - _adminLock.Lock(); - if (_source != nullptr) { - _source->Release(); - _source = nullptr; - } - - if (memory != nullptr) { - _source = memory; - _source->AddRef(); - } - _adminLock.Unlock(); - - _operational = (memory != nullptr); - } - - Core::ProxyType Source() const - { - Core::ProxyType source; - _adminLock.Lock(); - if(_source != nullptr) { - source = Core::ProxyType(*_source, *_source); - } - _adminLock.Unlock(); - return source; - } - - inline uint32_t Evaluate() - { - Core::ProxyType source = Source(); - - uint32_t status(SUCCESFULL); - if (source.IsValid() == true) { - _operationalSlots -= _interval; - _memorySlots -= _interval; - - if ((_operationalInterval != 0) && (_operationalSlots == 0)) { - _operational = source->IsOperational(); - if (_operational == false) { - status |= NOT_OPERATIONAL; - TRACE(Trace::Error, (_T("Status not operational. %d"), __LINE__)); - } - _operationalSlots = _operationalInterval; - } - if ((_memoryInterval != 0) && (_memorySlots == 0)) { - - uint64_t resident = source->Resident(); - uint64_t allocated = source->Allocated(); - uint64_t shared = source->Shared(); - uint64_t process = source->Processes(); - - _adminLock.Lock(); - _measurement.AddMeasurements(resident, allocated, shared, process); - _adminLock.Unlock(); - - if ((_memoryThreshold != 0) && (resident > _memoryThreshold)) { - status |= EXCEEDED_MEMORY; - TRACE(Trace::Error, (_T("Status MetaData Exceeded. %d"), __LINE__)); - } - _memorySlots = _memoryInterval; - } - } - return (status); - } - - bool IsActive() const { return _active; } - void Active(bool active) { _active = active; } - - private: - const uint32_t _operationalInterval; //!< Interval (s) to check the monitored processes - const uint32_t _memoryInterval; //!< Interval (s) for a memory measurement. - const uint64_t _memoryThreshold; //!< MetaData threshold in bytes for all processes. - uint32_t _operationalSlots; // does not need protection, only touched in job evaluate - uint32_t _memorySlots; // does not need protection, only touched in job evaluate - std::atomic _nextSlot; // no ordering needed, atomic should suffice - std::atomic _restartWindow; // no ordering needed, atomic should suffice - Core::Time _restartWindowStart; // only used in job (indirectly), no protection needed - uint32_t _restartCount; // only used in job (indirectly), no protection needed - std::atomic _restartLimit; // no ordering needed, atomic should suffice - MetaData _measurement; - std::atomic _operational; // no ordering needed, atomic should suffice - const bool _operationalEvaluate; - Exchange::IMemory* _source; - const uint32_t _interval; //!< The greatest possible interval to check both memory and processes. - std::atomic _active; - mutable Core::CriticalSection _adminLock; - }; - - public: - MonitorObjects(const MonitorObjects&) = delete; - MonitorObjects& operator=(const MonitorObjects&) = delete; - -PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST) - MonitorObjects(Monitor* parent) - : _monitor() - , _job(*this) - , _service(nullptr) - , _parent(*parent) - { - } -POP_WARNING() - ~MonitorObjects() override - { - ASSERT(_monitor.size() == 0); - } - - public: - inline uint32_t Length() const - { - return (static_cast(_monitor.size())); - } - inline void Update( - const string& observable, - const uint16_t restartWindow, - const uint8_t restartLimit) - { - MonitorObjectContainer::iterator index(_monitor.find(observable)); - if (index != _monitor.end()) { - index->second.UpdateRestartLimits( - restartWindow, - restartLimit); - } - } - inline void Open(PluginHost::IShell* service, Core::JSON::ArrayType::Iterator& index) - { - ASSERT((service != nullptr) && (_service == nullptr)); - - uint64_t baseTime = Core::Time::Now().Ticks(); - - _service = service; - _service->AddRef(); - - while (index.Next() == true) { - Config::Entry& element(index.Current()); - string callSign(element.Callsign.Value()); - uint64_t memoryThreshold(element.MetaDataLimit.Value()); - uint32_t interval = abs(element.Operational.Value()); - interval = interval * 1000 * 1000; // Move from Seconds to MicroSecond - uint32_t memory(element.MetaData.Value() * 1000 * 1000); // Move from Seconds to MicroSeconds - uint16_t restartWindow = 0; - uint8_t restartLimit = 0; - - if (element.Restart.IsSet()) { - restartWindow = element.Restart.Window; - restartLimit = element.Restart.Limit; - } - SYSLOG(Logging::Startup, (_T("Monitoring: %s (%d,%d)."), callSign.c_str(), (interval / 1000000), (memory / 1000000))); - if ((interval != 0) || (memory != 0)) { - - _monitor.emplace(std::piecewise_construct, - std::forward_as_tuple(callSign), - std::forward_as_tuple( - element.Operational.Value() >= 0, - interval, - memory, - memoryThreshold, - baseTime, - restartWindow, - restartLimit) - ); - } - } - - _job.Submit(); - } - inline void Close() - { - ASSERT(_service != nullptr); - - _job.Revoke(); - - _monitor.clear(); - _service->Release(); - _service = nullptr; - } - void Activated (const string& callsign, PluginHost::IShell* service) override - { - MonitorObjectContainer::iterator index(_monitor.find(callsign)); - - - if (index != _monitor.end()) { - - index->second.Active(true); - - // Get the MetaData interface - Exchange::IMemory* memory = service->QueryInterface(); - - if (memory != nullptr) { - index->second.Set(memory); - memory->Release(); - } - - if (_job.Submit() == true) { - TRACE(Trace::Information, (_T("Starting to probe as active observee appeared."))); - } - - } - - } - void Deactivated (const string& callsign, PluginHost::IShell* service) override - { - } - void Initialize(const string& callsign, PluginHost::IShell* service) override - { - } - void Deinitialized(const string& callsign, PluginHost::IShell* service) override - { - /* See comment in the Dispatch method on why no locking is here to protect the _monitor member */ - MonitorObjectContainer::iterator index(_monitor.find(callsign)); - - if (index != _monitor.end()) { - - index->second.Set(nullptr); - index->second.Active(false); - - PluginHost::IShell::reason reason = service->Reason(); - - if ((index->second.HasRestartAllowed() == true) && ((reason == PluginHost::IShell::MEMORY_EXCEEDED) || (reason == PluginHost::IShell::FAILURE))) { - if (index->second.RegisterRestart(reason) == false) { - uint8_t restartlimit = index->second.RestartLimit(); - uint16_t restartwindow = index->second.RestartWindow(); - TRACE(Trace::Fatal, (_T("Giving up restarting of %s: Failed more than %d times within %d seconds."), callsign.c_str(), restartlimit, restartwindow)); - const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Restart\", \"reason\":\"" + (std::to_string(restartlimit)).c_str() + " Attempts Failed within the restart window\"}"); - _service->Notify(message); - _parent.event_action(callsign, "StoppedRestaring", std::to_string(index->second.RestartLimit()) + " attempts failed within the restart window"); - } else { - const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Activate\", \"reason\": \"Automatic\" }"); - _service->Notify(message); - _parent.event_action(callsign, "Activate", "Automatic"); - TRACE(Trace::Error, (_T("Restarting %s again because we detected it misbehaved."), callsign.c_str())); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(service, PluginHost::IShell::ACTIVATED, PluginHost::IShell::AUTOMATIC)); - } - } - } - - } - void Unavailable(const string&, PluginHost::IShell*) override - { - } - void Snapshot(Core::JSON::ArrayType& snapshot) const - { - MonitorObjectContainer::const_iterator element(_monitor.cbegin()); - - // Go through the list of observations... - while (element != _monitor.cend()) { - MetaData data = element->second.Measurement(); - if (data.HasMeasurements() == true) { - snapshot.Add(Monitor::Data(element->first, data, element->second.Operational())); - } - element++; - } - - } - bool Snapshot(const string& name, Monitor::MetaData& result, bool& operational) const - { - bool found = false; - - - MonitorObjectContainer::const_iterator index(_monitor.find(name)); - - if (index != _monitor.cend()) { - MetaData data = index->second.Measurement(); - if (data.HasMeasurements() == true) { - result = data; - operational = index->second.Operational(); - found = true; - } - } - - return (found); - } - - void AddElementToRespone( Core::JSON::ArrayType& response, const string& callsign, const MonitorObject& object) const { - const MetaData& metaData = object.Measurement(); - JsonData::Monitor::InfoInfo info; - info.Observable = callsign; - - if (object.HasRestartAllowed()) { - info.Restart.Limit = object.RestartLimit(); - info.Restart.Window = object.RestartWindow(); - } - - if (metaData.HasMeasurements() == true) { - translate(metaData.Allocated(), &info.Measurements.Allocated); - translate(metaData.Resident(), &info.Measurements.Resident); - translate(metaData.Shared(), &info.Measurements.Shared); - translate(metaData.Process(), &info.Measurements.Process); - } - info.Measurements.Operational = object.Operational(); - info.Measurements.Count = metaData.Allocated().Measurements(); - - response.Add(info); - }; - - void Snapshot(const string& callsign, Core::JSON::ArrayType* response) const - { - - ASSERT(response != nullptr); - - if (callsign.empty() == false) { - auto element = _monitor.find(callsign); - if (element != _monitor.end()) { - AddElementToRespone(*response, element->first, element->second); - } - } else { - for (auto& element : _monitor) { - AddElementToRespone(*response, element.first, element.second); - } - } - } - - bool Reset(const string& name, Monitor::MetaData& result, bool& operational) - { - bool found = false; - - MonitorObjectContainer::iterator index(_monitor.find(name)); - - if (index != _monitor.end()) { - result = index->second.Measurement(); - operational = index->second.Operational(); - index->second.Reset(); - found = true; - } - - return (found); - } - - bool Reset(const string& name) - { - bool found = false; - - MonitorObjectContainer::iterator index(_monitor.find(name)); - - if (index != _monitor.end()) { - index->second.Reset(); - found = true; - } - - return (found); - } - - BEGIN_INTERFACE_MAP(MonitorObjects) - INTERFACE_ENTRY(PluginHost::IPlugin::INotification) - INTERFACE_ENTRY(PluginHost::IPlugin::ILifeTime) - END_INTERFACE_MAP - - private: - friend Core::ThreadPool::JobType; - - void Dispatch() - { - uint64_t scheduledTime(Core::Time::Now().Ticks()); - uint64_t nextSlot(static_cast(~0)); - - MonitorObjectContainer::iterator index(_monitor.begin()); - - // Go through the list of pending observations... - while (index != _monitor.end()) { - MonitorObject& info(index->second); - if (info.IsActive() == false) { - ++index; - continue; - } - - if (info.TimeSlot() <= scheduledTime) { - uint32_t value(info.Evaluate()); - - if ((value & (MonitorObject::NOT_OPERATIONAL | MonitorObject::EXCEEDED_MEMORY)) != 0) { - PluginHost::IShell* plugin(_service->QueryInterfaceByCallsign(index->first)); - - if (plugin != nullptr) { - Core::EnumerateType why(((value & MonitorObject::EXCEEDED_MEMORY) != 0) ? PluginHost::IShell::MEMORY_EXCEEDED : PluginHost::IShell::FAILURE); - - const string message("{\"callsign\": \"" + plugin->Callsign() + "\", \"action\": \"Deactivate\", \"reason\": \"" + why.Data() + "\" }"); - SYSLOG(Logging::Fatal, (_T("FORCED Shutdown: %s by reason: %s."), plugin->Callsign().c_str(), why.Data())); - - _service->Notify(message); - - _parent.event_action(plugin->Callsign(), "Deactivate", why.Data()); - - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(plugin, PluginHost::IShell::DEACTIVATED, why.Value())); - - plugin->Release(); - } - } - info.Retrigger(scheduledTime); - } - - if (info.TimeSlot() < nextSlot) { - nextSlot = info.TimeSlot(); - } - - index++; - } - - if (nextSlot != static_cast(~0)) { - if (nextSlot < Core::Time::Now().Ticks()) { - _job.Submit(); - } else { - nextSlot += 1000 /* Add 1 ms */; - _job.Reschedule(nextSlot); - } - } else { - TRACE(Trace::Information, (_T("Stopping to probe due to lack of active observees."))); - } - } - - private: - template - void translate(const Core::MeasurementType& from, JsonData::Monitor::MeasurementInfo* to) const - { - to->Min = from.Min(); - to->Max = from.Max(); - to->Average = from.Average(); - to->Last = from.Last(); - } - - private: - - using MonitorObjectContainer = std::unordered_map; - - MonitorObjectContainer _monitor; - Core::WorkerPool::JobType _job; - PluginHost::IShell* _service; - Monitor& _parent; - }; - - public: -PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST) - Monitor() - : _skipURL(0) - , _monitor(this) - { - } -POP_WARNING() - ~Monitor() = default; - - BEGIN_INTERFACE_MAP(Monitor) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IWeb) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - public: - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - - // First time initialization. Whenever a plugin is loaded, it is offered a Service object with relevant - // information and services for this particular plugin. The Service object contains configuration information that - // can be used to initialize the plugin correctly. If Initialization succeeds, return nothing (empty string) - // If there is an error, return a string describing the issue why the initialisation failed. - // The Service object is *NOT* reference counted, lifetime ends if the plugin is deactivated. - // The lifetime of the Service object is guaranteed till the deinitialize method is called. - const string Initialize(PluginHost::IShell* service) override; - - // The plugin is unloaded from WPEFramework. This is call allows the module to notify clients - // or to persist information if needed. After this call the plugin will unlink from the service path - // and be deactivated. The Service object is the same as passed in during the Initialize. - // After theis call, the lifetime of the Service object ends. - void Deinitialize(PluginHost::IShell* service) override; - - // Returns an interface to a JSON struct that can be used to return specific metadata information with respect - // to this plugin. This Metadata can be used by the MetData plugin to publish this information to the ouside world. - string Information() const override; - - // IWeb methods - // ------------------------------------------------------------------------------------------------------- - // Whenever a request is received, it might carry some additional data in the body. This method allows - // the plugin to attach a deserializable data object (ref counted) to be loaded with any potential found - // in the body of the request. - void Inbound(Web::Request& request) override; - - // If everything is received correctly, the request is passed on to us, through a thread from the thread pool, to - // do our thing and to return the result in the response object. Here the actual specific module work, - // based on a a request is handled. - Core::ProxyType Process(const Web::Request& request) override; - - private: - uint8_t _skipURL; - Config _config; - Core::Sink _monitor; - - private: - void RegisterAll(); - void UnregisterAll(); - uint32_t endpoint_restartlimits(const JsonData::Monitor::RestartlimitsParamsData& params); - uint32_t endpoint_resetstats(const JsonData::Monitor::ResetstatsParamsData& params, JsonData::Monitor::InfoInfo& response); - uint32_t get_status(const string& index, Core::JSON::ArrayType& response) const; - void event_action(const string& callsign, const string& action, const string& reason); - }; -} -} - -#endif // __MONITOR_H diff --git a/Monitor/Monitor.vcxproj b/Monitor/Monitor.vcxproj deleted file mode 100644 index 5402e7b..0000000 --- a/Monitor/Monitor.vcxproj +++ /dev/null @@ -1,185 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {614AEA75-493F-4DB4-897C-6A3EAF8C5781} - Win32Proj - Monitor - 10.0 - - - - DynamicLibrary - true - v142 - MultiByte - - - DynamicLibrary - false - v142 - true - MultiByte - - - DynamicLibrary - true - v142 - MultiByte - - - DynamicLibrary - false - v142 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - true - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - false - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - false - $(SolutionDir)..\artifacts\$(Configuration)\ - $(OutDir)Plugins\$(TargetName)\ - lib$(ProjectName) - .so - - - - NotUsing - Level3 - Disabled - true - _CRT_SECURE_NO_WARNINGS;_DEBUG;MONITOR_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - - - Windows - true - $(OutDir) - - - - - NotUsing - Level3 - Disabled - true - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;MONITOR_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - - - Windows - true - $(OutDir) - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;MONITOR_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - - - Windows - true - true - true - $(OutDir) - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;MONITOR_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - $(FrameworkPath);$(ContractsPath);$(WindowsPath);$(WindowsPath)zlib - - - Windows - true - true - true - $(OutDir) - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Monitor/Monitor.vcxproj.filters b/Monitor/Monitor.vcxproj.filters deleted file mode 100644 index 74beee4..0000000 --- a/Monitor/Monitor.vcxproj.filters +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - {430e0438-d0b1-4d26-b0fa-5dae187ef5fb} - - - {0df0c7ce-0888-441a-9ac7-c96ef899854d} - - - \ No newline at end of file diff --git a/Monitor/MonitorJsonRpc.cpp b/Monitor/MonitorJsonRpc.cpp deleted file mode 100644 index b53f40c..0000000 --- a/Monitor/MonitorJsonRpc.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" -#include "Monitor.h" -#include - -namespace WPEFramework { - -namespace Plugin { - - using namespace JsonData::Monitor; - - // Registration - // - - void Monitor::RegisterAll() - { - Register(_T("restartlimits"), &Monitor::endpoint_restartlimits, this); - Register(_T("resetstats"), &Monitor::endpoint_resetstats, this); - Property>(_T("status"), &Monitor::get_status, nullptr, this); - } - - void Monitor::UnregisterAll() - { - Unregister(_T("resetstats")); - Unregister(_T("restartlimits")); - Unregister(_T("status")); - } - - // API implementation - // - - // Method: restartlimits - Sets new restart limits for a plugin - // Return codes: - // - ERROR_NONE: Success - uint32_t Monitor::endpoint_restartlimits(const RestartlimitsParamsData& params) - { - const string& callsign = params.Callsign.Value(); - _monitor.Update( - callsign, - params.Restart.Window.Value(), params.Restart.Limit.Value()); - return Core::ERROR_NONE; - } - - // Method: resetstats - Resets memory and process statistics for a single plugin watched by the Monitor - // Return codes: - // - ERROR_NONE: Success - uint32_t Monitor::endpoint_resetstats(const ResetstatsParamsData& params, InfoInfo& response) - { - const string& callsign = params.Callsign.Value(); - - Core::JSON::ArrayType info; - _monitor.Snapshot(callsign, &info); - if (info.Length() == 1) { - _monitor.Reset(callsign); - response = info[0]; - } - return Core::ERROR_NONE; - } - - // Property: status - The memory and process statistics either for a single plugin or all plugins watched by the Monitor - // Return codes: - // - ERROR_NONE: Success - uint32_t Monitor::get_status(const string& index, Core::JSON::ArrayType& response) const - { - const string& callsign = index; - _monitor.Snapshot(callsign, &response); - return Core::ERROR_NONE; - } - - // Event: action - Signals action taken by the monitor - void Monitor::event_action(const string& callsign, const string& action, const string& reason) - { - ActionParamsData params; - params.Callsign = callsign; - params.Action = action; - params.Reason = reason; - - Notify(_T("action"), params); - } -} // namespace Plugin -} diff --git a/Monitor/doc/MonitorPlugin.md b/Monitor/doc/MonitorPlugin.md deleted file mode 100644 index bbb86cd..0000000 --- a/Monitor/doc/MonitorPlugin.md +++ /dev/null @@ -1,5 +0,0 @@ -The RDK Services documentation is hosted as a static web site. - -[View Latest Documentation](https://rdkcentral.github.io/rdkservices/#/README) - -This file will be removed in a future release. The API markdown files for RDK services are located in the [docs/api](https://github.com/rdkcentral/rdkservices/tree/main/docs/api) folder. Please update your bookmarks accordingly. diff --git a/NativeJS/CMakeLists.txt b/NativeJS/CMakeLists.txt deleted file mode 100644 index e3ad3b5..0000000 --- a/NativeJS/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -set(PLUGIN_NAME NativeJS) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) - -add_library(${MODULE_NAME} SHARED - NativeJSPlugin.cpp - NativeJSImplementation.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED YES) - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers $ENV{PKG_CONFIG_SYSROOT_DIR}/usr/include/jsruntime ${CMAKE_CURRENT_SOURCE_DIR} ) - -target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${NAMESPACE}Definitions::${NAMESPACE}Definitions -L${CMAKE_CURRENT_SOURCE_DIR}/../../build/NativeJS -L$ENV{PKG_CONFIG_SYSROOT_DIR}/usr/lib/javascriptcore -lJSRuntimeJSC -lJavaScriptCore) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/NativeJS/Module.cpp b/NativeJS/Module.cpp deleted file mode 100644 index ce759b6..0000000 --- a/NativeJS/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/NativeJS/Module.h b/NativeJS/Module.h deleted file mode 100644 index 9455042..0000000 --- a/NativeJS/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME NativeJS -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/NativeJS/NativeJS.conf.in b/NativeJS/NativeJS.conf.in deleted file mode 100644 index 50b1515..0000000 --- a/NativeJS/NativeJS.conf.in +++ /dev/null @@ -1,8 +0,0 @@ -autostart = "false" -precondition = ["Graphics"] -callsign = "org.rdk.jsruntime" -configuration = JSON() -root = JSON() -root.add("mode", "Local") -configuration.add("root", root) -configuration.add("clientidentifier", "test") diff --git a/NativeJS/NativeJS.config b/NativeJS/NativeJS.config deleted file mode 100644 index 7d97e99..0000000 --- a/NativeJS/NativeJS.config +++ /dev/null @@ -1,17 +0,0 @@ -set (autostart false) -set (preconditions Graphics) -set (callsign "org.rdk.jsruntime") - -map() - kv(outofprocess true) -end() -ans(rootobject) - -map() - if(PLUGIN_NATIVEJS_CLIENTIDENTIFIER) - kv(clientidentifier ${PLUGIN_NATIVEJS_CLIENTIDENTIFIER}) - endif() -end() -ans(configuration) - -map_append(${configuration} root ${rootobject}) diff --git a/NativeJS/NativeJSImplementation.cpp b/NativeJS/NativeJSImplementation.cpp deleted file mode 100644 index d52ff21..0000000 --- a/NativeJS/NativeJSImplementation.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "NativeJSImplementation.h" - -using namespace std; - -namespace WPEFramework -{ - namespace Plugin - { - - std::string gPendingIdRequest(""); - std::string gPendingIdOptionsRequest(""); - std::string gPendingUrl(""); - SERVICE_REGISTRATION(NativeJSImplementation, 1, 0); - - NativeJSImplementation::NativeJSImplementation() - : mRunning(true) - { - TRACE(Trace::Information, (_T("Constructing NativeJSImplementation Service: %p"), this)); - } - - NativeJSImplementation::~NativeJSImplementation() - { - TRACE(Trace::Information, (_T("Destructing NativeJSImplementation Service: %p"), this)); - mNativeJSRenderer = nullptr; - } - - Core::hresult NativeJSImplementation::Initialize(string waylandDisplay) - { - std::cout << "initialize called on nativejs implementation " << std::endl; - mRenderThread = std::thread([=](std::string waylandDisplay) { - mNativeJSRenderer = std::make_shared(waylandDisplay); - //if (!gPendingUrlRequest.empty()) - //{ - // ModuleSettings moduleSettings; - // moduleSettings.fromString(gPendingUrlOptionsRequest); - // mNativeJSRenderer->launchApplication(gPendingUrlRequest, moduleSettings); - // gPendingUrlRequest = ""; - // gPendingUrlOptionsRequest = ""; - //} - - mNativeJSRenderer->run(); - - printf("After launch application execution ... \n"); fflush(stdout); - mNativeJSRenderer.reset(); - - }, waylandDisplay); - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::Deinitialize() - { - LOGINFO("deinitializing NativeJS process"); - if (mNativeJSRenderer) - { - mNativeJSRenderer->terminate(); - if (mRenderThread.joinable()) - { - mRenderThread.join(); - } - } - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::CreateApplication(const std::string options, uint32_t& id) - { - LOGINFO("createApplication invoked"); - if(mNativeJSRenderer) - { - std::string optionsVal(options); - ModuleSettings moduleSettings; - moduleSettings.fromString(optionsVal); - id = mNativeJSRenderer->createApplication(moduleSettings); - } - else - { - gPendingIdOptionsRequest = options; - } - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::RunApplication(uint32_t id, const std::string url) - { - LOGINFO("runApplication invoked"); - if(mNativeJSRenderer) - { - std::string Url(url); - mNativeJSRenderer->runApplication(id, Url); - } - else - { - gPendingUrl = url; - LOGINFO("runApplication Couldn't execute"); - } - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::RunJavaScript(uint32_t id, const std::string code) - { - LOGINFO("runJavaScript invoked"); - if(mNativeJSRenderer) - { - std::string Code(code); - mNativeJSRenderer->runJavaScript(id, Code); - } - else - { - LOGINFO("runJavaScript couldn't execute"); - } - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::GetApplications() - { - LOGINFO("getApplication invoked"); - if(mNativeJSRenderer) - { - mNativeJSRenderer->getApplications(); - } - else - { - LOGINFO("getApplication couldn't execute"); - } - return (Core::ERROR_NONE); - } - - Core::hresult NativeJSImplementation::TerminateApplication(uint32_t id) - { - LOGINFO("terminateApplication invoked"); - if(mNativeJSRenderer) - { - mNativeJSRenderer->terminateApplication(id); - } - else - { - LOGINFO("Application couldn't be terminated"); - } - return (Core::ERROR_NONE); - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/NativeJS/NativeJSImplementation.h b/NativeJS/NativeJSImplementation.h deleted file mode 100644 index cc3b9d7..0000000 --- a/NativeJS/NativeJSImplementation.h +++ /dev/null @@ -1,61 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include "UtilsLogging.h" -#include -#include - -#include -#include "NativeJSRenderer.h" -#include -#include -using namespace JsRuntime; - -namespace WPEFramework -{ - namespace Plugin - { - - class NativeJSImplementation : public Exchange::INativeJS - { - public: - NativeJSImplementation(); - virtual ~NativeJSImplementation(); - virtual Core::hresult Initialize(const string waylandDisplay) override; - virtual Core::hresult Deinitialize() override; - virtual Core::hresult CreateApplication(const std::string options, uint32_t& id) override; - virtual Core::hresult GetApplications() override; - virtual Core::hresult RunApplication(uint32_t id, const std::string url) override; - virtual Core::hresult RunJavaScript(uint32_t id, const std::string code) override; - virtual Core::hresult TerminateApplication(uint32_t id) override; - - BEGIN_INTERFACE_MAP(NativeJSImplementation) - INTERFACE_ENTRY(Exchange::INativeJS) - END_INTERFACE_MAP - - private: - std::thread mRenderThread; - bool mRunning; - std::shared_ptr mNativeJSRenderer; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/NativeJS/NativeJSPlugin.cpp b/NativeJS/NativeJSPlugin.cpp deleted file mode 100644 index 03fcb3b..0000000 --- a/NativeJS/NativeJSPlugin.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "NativeJSPlugin.h" - -const string WPEFramework::Plugin::NativeJS::SERVICE_NAME = "org.rdk.NativeJS"; - -using namespace std; - -namespace WPEFramework { - namespace Plugin { - - SERVICE_REGISTRATION(NativeJS, 1, 0); - - NativeJS* NativeJS::_instance = nullptr; - - NativeJS::NativeJS() - : PluginHost::IPlugin(), PluginHost::JSONRPC(), mService(nullptr), mNativeJS(nullptr) - { - NativeJS::_instance = this; - } - - NativeJS::~NativeJS() - { - } - - const string NativeJS::Initialize(PluginHost::IShell* service ) - { - string message; - - ASSERT(mService == nullptr); - ASSERT(mNativeJS == nullptr); - - mConnectionId = 0; - mService = service; - - mNativeJS = mService->Root(mConnectionId, 5000, _T("NativeJSImplementation")); - - if (mNativeJS == nullptr) - { - message = _T("NativeJS implementation could not be instantiated."); - mService = nullptr; - return message; - } - std::string waylandDisplay(""); - mConfig.FromString(service->ConfigLine()); - if (mConfig.Display.IsSet() == true) - { - waylandDisplay = mConfig.Display.Value(); - } - else - { - const char* display = getenv("WAYLAND_DISPLAY"); - if (NULL != display) - { - waylandDisplay = display; - } - } - mNativeJS->Initialize(waylandDisplay); - Exchange::JNativeJS::Register(*this, mNativeJS); - return ""; - } - - void NativeJS::Deinitialize(PluginHost::IShell* /* service */) - { - LOGINFO("Deinitializing NativeJS instance"); - if (mNativeJS != nullptr) { - - Exchange::JNativeJS::Unregister(*this); - mNativeJS->Deinitialize(); - - mNativeJS->Release(); - mNativeJS = nullptr; - mService = nullptr; - NativeJS::_instance = nullptr; - LOGINFO("NativeJS deinitialized successfully"); - - } - } - - string NativeJS::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - - } // namespace Plugin -} // namespace WPEFramework diff --git a/NativeJS/NativeJSPlugin.h b/NativeJS/NativeJSPlugin.h deleted file mode 100644 index 64ab701..0000000 --- a/NativeJS/NativeJSPlugin.h +++ /dev/null @@ -1,88 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include "UtilsLogging.h" -#include "UtilsJsonRpc.h" -#include -#include -#include - -namespace WPEFramework { - - namespace Plugin { - - class NativeJS : public PluginHost::IPlugin, public PluginHost::JSONRPC { - public: - class Config : public Core::JSON::Container - { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - public: - Config() - : Core::JSON::Container() - , Display(_T("")) - { - Add(_T("embedthunderjs"), &EmbedThunderJS); - Add(_T("clientidentifier"), &Display); - } - ~Config() - { - } - - public: - Core::JSON::Boolean EmbedThunderJS; - Core::JSON::String Display; - }; - - BEGIN_INTERFACE_MAP(NativeJSPlugin) - INTERFACE_AGGREGATE(Exchange::INativeJS, mNativeJS) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - public: - NativeJS(); - virtual ~NativeJS(); - virtual const string Initialize(PluginHost::IShell* service) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override; - - public/*members*/: - static NativeJS* _instance; - - public /*constants*/: - static const string SERVICE_NAME; - - private/*registered methods (wrappers)*/: - - NativeJS(const NativeJS&) = delete; - NativeJS& operator=(const NativeJS&) = delete; - - PluginHost::IShell* mService; - uint32_t mConnectionId; - Exchange::INativeJS* mNativeJS; - Config mConfig; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/NativeJS/README.md b/NativeJS/README.md deleted file mode 100644 index b3d0265..0000000 --- a/NativeJS/README.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------ -# NativeJS - -## Versions -`org.rdk.jsruntime.1` - -## Properties: -``` -## Methods: -``` -TO laucnch the application -curl --header "Content-Type: application/json"  -H "$token" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.jsruntime.1.launchApplication", "params":{"url":"http://127.0.0.1:50050/demo/helloworld.js"}}' http://127.0.0.1:9998/jsonrpc - -Destory the application -curl --header "Content-Type: application/json" -H "$token" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.jsruntime.1.destroyApplication", "params":{"url":"http://127.0.0.1:50050/demo/player.js"}' http://127.0.0.1:9998/jsonrpc - -To play video content on display, pass player in options parameter -curl --header "Content-Type: application/json"  -H "$token" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.jsruntime.1.launchApplication", "params":{"url":"http://127.0.0.1:50050/demo/helloworld.js", "options": "player"}}' http://127.0.0.1:9998/jsonrpc -``` -## Responses -``` -{"jsonrpc":"2.0","id":3,"result":null} - -``` - -## Events -``` -none -``` - -## Full Reference diff --git a/OCIContainer/CHANGELOG.md b/OCIContainer/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/OCIContainer/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/OCIContainer/CMakeLists.txt b/OCIContainer/CMakeLists.txt deleted file mode 100644 index 380f76d..0000000 --- a/OCIContainer/CMakeLists.txt +++ /dev/null @@ -1,114 +0,0 @@ -### -# If not stated otherwise in this file or this component's LICENSE -# file the following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -### - -set(PLUGIN_NAME OCIContainer) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(PLUGIN_OCICONTAINER_STARTUPORDER "" CACHE STRING "To configure startup order of OCIContainer plugin") - -find_package(PkgConfig) -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) -find_package(Dobby CONFIG) - -# Temporary fix to get defines in Dobby. Will be removed later. -add_definitions( -DRDK ) - -pkg_search_module(OMI_CLIENT "omiclientlib") - -if(NOT OMI_CLIENT_FOUND) - if(NOT RDK_SERVICE_L2_TEST) - set(OMI_CLIENT_INCLUDE_DIRS stubs) - message("Using stubs for omiclientlib") - else() - message("RDK_SERVICE_L2_TEST is enabled, not using stubs for omiclientlib") - endif() -endif() - -add_definitions(-DOCICONTAINER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DOCICONTAINER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DOCICONTAINER_API_VERSION_NUMBER_PATCH=0) - -add_library(${MODULE_NAME} SHARED - OCIContainer.cpp - OCIContainerImplementation.cpp - DobbyInterface.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(OCIContainer.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -list(APPEND CMAKE_MODULE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") - -# We need libsystemd since we're using their dbus library (sd-bus) -# There's probably a better way of doing this... -find_path(SYSTEMD_INCLUDE_DIRS - NAMES systemd/sd-bus.h -) - -find_library(SYSTEMD_LIBRARIES - NAMES systemd -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - LIBSYSTEMD - SYSTEMD_LIBRARIES SYSTEMD_INCLUDE_DIRS -) - -target_include_directories(${MODULE_NAME} - PRIVATE - ../helpers - ${OMI_CLIENT_INCLUDE_DIRS} -) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${DOBBY_LIBRARIES} - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions - ${SYSTEMD_LIBRARIES} - ${OMI_CLIENT_LIBRARIES} -) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${MODULE_NAME} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - target_include_directories(${MODULE_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/../../entservices-infra/entservices-testframework/Tests/mocks - ) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICE_L2_TEST) - -# ${NAMESPACE}Protocols::${NAMESPACE}Protocols -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/OCIContainer/DobbyInterface.cpp b/OCIContainer/DobbyInterface.cpp deleted file mode 100644 index 36f86c4..0000000 --- a/OCIContainer/DobbyInterface.cpp +++ /dev/null @@ -1,889 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include - -#include "DobbyInterface.h" - -#include -#include -#include -#include "UtilsJsonRpc.h" - -namespace WPEFramework -{ -namespace Plugin -{ -namespace WPEC = WPEFramework::Core; -namespace WPEJ = WPEFramework::Core::JSON; - -DobbyInterface::DobbyInterface(): mEventHandler(nullptr) -{ -} - -DobbyInterface::~DobbyInterface() -{ -} - -bool DobbyInterface::initialize(IEventHandler* eventHandler) -{ - mEventHandler = eventHandler; - mIpcService = AI_IPC::createIpcService("unix:path=/var/run/dbus/system_bus_socket", "com.sky.dobby.thunder"); - - if (!mIpcService) - { - LOGERR("Failed to create IPC service"); - return false; - } - else - { - // Start the IPCService which kicks off the event dispatcher thread - mIpcService->start(); - } - - // Create a DobbyProxy remote service that wraps up the dbus API - // calls to the Dobby daemon - mDobbyProxy = std::make_shared(mIpcService, DOBBY_SERVICE, DOBBY_OBJECT); - - // Register a state change event listener - mEventListenerId = mDobbyProxy->registerListener(stateListener, static_cast(this)); - - mOmiProxy = std::make_shared(); - - mOmiListenerId = mOmiProxy->registerListener(omiErrorListener, static_cast(this)); - - return true; -} - -void DobbyInterface::terminate() -{ - mEventHandler = nullptr; - mDobbyProxy->unregisterListener(mEventListenerId); - mOmiProxy->unregisterListener(mOmiListenerId); -} - -bool DobbyInterface::listContainers(string& containers, string& errorReason) -{ - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - // Get the running containers from Dobby - std::list> runningContainers; - JsonObject containerJson; - JsonArray containerArray; - - runningContainers = mDobbyProxy->listContainers(); - - // Build the response if containers were found - if (!runningContainers.empty()) - { - for (const std::pair& c : runningContainers) - { - containerJson["Descriptor"] = c.first; - containerJson["Id"] = c.second; - - containerArray.Add(containerJson); - } - } - - if (!WPEFramework::Core::JSON::IElement::ToString(containerArray, containers)) - { - errorReason = "Failed to convert Dobby spec to string"; - return false; - } - return true; -} - -bool DobbyInterface::getContainerState(const string& containerId, Exchange::IOCIContainer::ContainerState& state, string& errorReason) -{ - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - int cd = GetContainerDescriptorFromId(containerId); - if (cd < 0) - { - state = Exchange::IOCIContainer::ContainerState::INVALID; - return false; - } - - // We got a state back successfully, work out what that means in English - switch (static_cast(mDobbyProxy->getContainerState(cd))) - { - case IDobbyProxyEvents::ContainerState::Invalid: - state = Exchange::IOCIContainer::ContainerState::INVALID; - break; - case IDobbyProxyEvents::ContainerState::Starting: - state = Exchange::IOCIContainer::ContainerState::STARTING; - break; - case IDobbyProxyEvents::ContainerState::Running: - state = Exchange::IOCIContainer::ContainerState::RUNNING; - break; - case IDobbyProxyEvents::ContainerState::Stopping: - state = Exchange::IOCIContainer::ContainerState::STOPPING; - break; - case IDobbyProxyEvents::ContainerState::Paused: - state = Exchange::IOCIContainer::ContainerState::PAUSED; - break; - case IDobbyProxyEvents::ContainerState::Stopped: - state = Exchange::IOCIContainer::ContainerState::STOPPED; - break; - case IDobbyProxyEvents::ContainerState::Hibernating: - state = Exchange::IOCIContainer::ContainerState::HIBERNATING; - break; - case IDobbyProxyEvents::ContainerState::Hibernated: - state = Exchange::IOCIContainer::ContainerState::HIBERNATED; - break; - case IDobbyProxyEvents::ContainerState::Awakening: - state = Exchange::IOCIContainer::ContainerState::AWAKENING; - break; - default: - state = Exchange::IOCIContainer::ContainerState::INVALID; - break; - } - - return true; -} - -bool DobbyInterface::getContainerInfo(const string& containerId, string& info, string& errorReason) -{ - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - info = mDobbyProxy->getContainerInfo(cd); - - if (info.empty()) - { - errorReason = "Failed to get info for container"; - return false; - } - - return true; -} - -static bool is_encrypted(const std::string &bundlePath) { - struct stat st; - - std::string str = bundlePath + "rootfs.img"; - - if (stat(str.c_str(), &st)) - { - return false; - } - - if (!(st.st_mode & S_IFREG || st.st_mode & S_IFLNK)) - { - return false; - } - - str = bundlePath + "config.json.jwt"; - - if (stat(str.c_str(), &st)) - { - return false; - } - - if (!(st.st_mode & S_IFREG || st.st_mode & S_IFLNK)) - { - return false; - } - - return true; -} - -bool DobbyInterface::startContainer(const string& containerId, const string& bundlePath, const string& command, const string& westerosSocket, int32_t& descriptor, string& errorReason) -{ - LOGINFO("Start container from OCI bundle"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - // Can be used to pass file descriptors to container construction. - // Currently unsupported, see DobbyProxy::startContainerFromBundle(). - std::list emptyList; - - std::string containerPath; - - const bool encrypted = is_encrypted(bundlePath); - - if (encrypted && !mOmiProxy->mountCryptedBundle(id, - bundlePath + "rootfs.img", - bundlePath + "config.json.jwt", - containerPath)) - { - LOGERR("Failed to start container - sync mount request to omi failed."); - errorReason = "mount failed"; - return false; - } - - if (encrypted) - { - LOGINFO("Mount request to omi succeeded, contenerPath: %s", containerPath.c_str()); - } - - - // If no additional arguments, start the container - if ((command == "null" || command.empty()) && (westerosSocket == "null" || westerosSocket.empty())) - { - LOGINFO("startContainerFromBundle: id: %s, containerPath: %s", id.c_str(), encrypted ? containerPath.c_str() : bundlePath.c_str()); - descriptor = mDobbyProxy->startContainerFromBundle(id, encrypted ? containerPath : bundlePath, emptyList); - } - else - { - std::string commandModified = command, westerosSocketModified = westerosSocket; - // Dobby expects empty strings if values not set - if (command == "null" || command.empty()) - { - commandModified = ""; - } - if (westerosSocket == "null" || westerosSocket.empty()) - { - westerosSocketModified = ""; - } - - LOGINFO("startContainerFromBundle: id: %s, containerPath: %s, command: %s, westerosSocket: %s", id.c_str(), encrypted ? containerPath.c_str() : bundlePath.c_str(), commandModified.c_str(), westerosSocketModified.c_str()); - descriptor = mDobbyProxy->startContainerFromBundle(id, encrypted ? containerPath : bundlePath, emptyList, commandModified, westerosSocketModified); - } - - // startContainer returns -1 on failure - if (descriptor <= 0) - { - LOGERR("Failed to start container - internal Dobby error."); - - if (encrypted && !mOmiProxy->umountCryptedBundle(id.c_str())) - { - LOGERR("Failed to umount container %s - sync unmount request to omi failed.", id.c_str()); - errorReason = "dobby start failed, unmount failed"; - } - else - { - errorReason = "dobby start failed"; - } - - return false; - } - - return true; -} - -bool DobbyInterface::startContainerFromDobbySpec(const string& containerId, const string& dobbySpec, const string& command, const string& westerosSocket, int32_t& descriptor, string& errorReason) -{ - LOGINFO("Start container from Dobby spec"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - // To start a container, we need a Dobby spec and an ID for the container - std::string id = containerId; - - // Can be used to pass file descriptors to container construction. - // Currently unsupported, see DobbyProxy::startContainerFromSpec(). - std::list emptyList; - - // If no additional arguments, start the container - if ((command == "null" || command.empty()) && (westerosSocket == "null" || westerosSocket.empty())) - { - descriptor = mDobbyProxy->startContainerFromSpec(id, dobbySpec, emptyList); - } - else - { - std::string commandModified = command, westerosSocketModified = westerosSocket; - // Dobby expects empty strings if values not set - if (command == "null" || command.empty()) - { - commandModified = ""; - } - if (westerosSocket == "null" || westerosSocket.empty()) - { - westerosSocketModified = ""; - } - descriptor = mDobbyProxy->startContainerFromSpec(id, dobbySpec, emptyList, commandModified, westerosSocketModified); - } - - // startContainer returns -1 on failure - if (descriptor <= 0) - { - LOGERR("Failed to start container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::stopContainer(const string& containerId, bool force, string& errorReason) -{ - LOGINFO("Stop container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - // Need to have an ID to stop - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - errorReason = "Container not found"; - return false; - } - - bool forceStop = force; - LOGINFO("Force stop is %d", forceStop); - - bool stoppedSuccessfully = mDobbyProxy->stopContainer(cd, forceStop); - - if (!stoppedSuccessfully) - { - LOGERR("Failed to stop container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::pauseContainer(const string& containerId, string& errorReason) -{ - LOGINFO("Pause container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - // Need to have an ID to pause - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool pausedSuccessfully = mDobbyProxy->pauseContainer(cd); - - if (!pausedSuccessfully) - { - LOGERR("Failed to pause container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::resumeContainer(const string& containerId, string& errorReason) -{ - LOGINFO("Resume container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - // Need to have an ID to resume - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool resumedSuccessfully = mDobbyProxy->resumeContainer(cd); - - if (!resumedSuccessfully) - { - LOGERR("Failed to resume container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::hibernateContainer(const string& containerId, const string& options, string& errorReason) -{ - LOGINFO("Hibernate container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - // Need to have an ID to resume - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool hibernateSuccessfully = mDobbyProxy->hibernateContainer(cd, options); - - if (!hibernateSuccessfully) - { - LOGERR("Failed to hibernate container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::wakeupContainer(const string& containerId, string& errorReason) -{ - LOGINFO("wakeup container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - // Need to have an ID to resume - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool wakedUpSuccessfully = mDobbyProxy->wakeupContainer(cd); - - if (!wakedUpSuccessfully) - { - LOGERR("Failed to wakeup container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::executeCommand(const string& containerId, const string& options, const string& command, string& errorReason) -{ - LOGINFO("Execute command inside container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool executedSuccessfully = mDobbyProxy->execInContainer(cd, options, command); - - if (!executedSuccessfully) - { - LOGERR("Failed to execute command in container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::annotate(const string& containerId, const string& key, const string& value, string& errorReason) -{ - LOGINFO("Add annotation in container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool annotatedSuccessfully = mDobbyProxy->addAnnotation(cd, key, value); - - if (!annotatedSuccessfully) - { - LOGERR("Failed to add annotation in container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::removeAnnotation(const string& containerId, const string& key, string& errorReason) -{ - LOGINFO("remove annotation in container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool removeAnnotationSuccessfully = mDobbyProxy->removeAnnotation(cd, key); - - if (!removeAnnotationSuccessfully) - { - LOGERR("Failed to remove annotation in container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::mount(const string& containerId, const string& source, const string& target, const string& type, const string& options, string& errorReason) -{ - LOGINFO("mount in container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - std::vector mountFlags; - //TODO Populate mount flags and data - bool mountSuccessfully = mDobbyProxy->addContainerMount(cd, source, target, mountFlags, ""); - - if (!mountSuccessfully) - { - LOGERR("Failed to mount in container - internal Dobby error."); - return false; - } - - return true; -} - -bool DobbyInterface::unmount(const string& containerId, const string& target, string& errorReason) -{ - LOGINFO("unmount from container"); - if (nullptr == mDobbyProxy) - { - errorReason = "dobby environment is not ready"; - return false; - } - - std::string id = containerId; - - int cd = GetContainerDescriptorFromId(id); - if (cd < 0) - { - return false; - } - - bool unmountSuccessfully = mDobbyProxy->removeContainerMount(cd, target); - - if (!unmountSuccessfully) - { - LOGERR("Failed to unmount from container - internal Dobby error."); - return false; - } - - return true; -} - -/** - * @brief Send an event notifying that a container has started. - * - * @param descriptor Container descriptor. - * @param name Container name. - */ -void DobbyInterface::onContainerStarted(int32_t descriptor, const std::string& name) -{ - JsonObject params; - params["descriptor"] = std::to_string(descriptor); - params["name"] = name; - - string containerId = GetContainerIdFromDescriptor(descriptor); - params["containerId"] = (containerId.empty()) ? name : containerId; - - if (mEventHandler) - { - mEventHandler->onContainerStarted(params); - } -} - -/** - * @brief Send an event notifying that a container has stopped. - * - * @param descriptor Container descriptor. - * @param name Container name. - */ -void DobbyInterface::onContainerStopped(int32_t descriptor, const std::string& name) -{ - - if (!mOmiProxy->umountCryptedBundle(name)) - { - LOGERR("Failed to umount container %s - sync unmount request to omi failed.", name.c_str()); - } - else - { - LOGINFO("Container %s properly unmounted.", name.c_str()); - } - - JsonObject params; - params["descriptor"] = std::to_string(descriptor); - params["name"] = name; - string containerId = GetContainerIdFromDescriptor(descriptor); - params["containerId"] = (containerId.empty()) ? name : containerId; - - if (mEventHandler) - { - mEventHandler->onContainerStopped(params); - } -} - -void DobbyInterface::onContainerStateChanged(int32_t descriptor, const std::string& name, IDobbyProxyEvents::ContainerState dobbyContainerState) -{ - Exchange::IOCIContainer::ContainerState state ; - switch (dobbyContainerState) - { - case IDobbyProxyEvents::ContainerState::Starting: - state = Exchange::IOCIContainer::ContainerState::STARTING; - break; - case IDobbyProxyEvents::ContainerState::Running: - state = Exchange::IOCIContainer::ContainerState::RUNNING; - break; - case IDobbyProxyEvents::ContainerState::Stopping: - state = Exchange::IOCIContainer::ContainerState::STOPPING; - break; - case IDobbyProxyEvents::ContainerState::Paused: - state = Exchange::IOCIContainer::ContainerState::PAUSED; - break; - case IDobbyProxyEvents::ContainerState::Stopped: - state = Exchange::IOCIContainer::ContainerState::STOPPED; - break; - case IDobbyProxyEvents::ContainerState::Hibernating: - state = Exchange::IOCIContainer::ContainerState::HIBERNATING; - break; - case IDobbyProxyEvents::ContainerState::Hibernated: - state = Exchange::IOCIContainer::ContainerState::HIBERNATED; - break; - case IDobbyProxyEvents::ContainerState::Awakening: - state = Exchange::IOCIContainer::ContainerState::AWAKENING; - break; - default: - state = Exchange::IOCIContainer::ContainerState::INVALID; - break; - } - JsonObject params; - params["state"] = static_cast(state); - string containerId = GetContainerIdFromDescriptor(descriptor); - params["containerId"] = (containerId.empty()) ? name : containerId; - - LOGINFO("OnContainerStateChanged event state %u",static_cast(state)); - - if (mEventHandler) - { - mEventHandler->onContainerStateChange(params); - } -} - -// Begin Internal Methods - -/** - * @brief Converts the OCI container ID into the internal Dobby descriptor int - * - * Will only return a value if Dobby knows about the running container - * (e.g. the container was started by Dobby, not manually using the OCI runtime). - * - * @param containerId The container ID used by the OCI runtime - not the Dobby descriptor - * - * @return Descriptor value - */ -const int DobbyInterface::GetContainerDescriptorFromId(const std::string& containerId) -{ - const std::list> containers = mDobbyProxy->listContainers(); - - for (const std::pair& container : containers) - { - char strDescriptor[32]; - snprintf(strDescriptor, sizeof(strDescriptor), "%d", container.first); - - if ((containerId == strDescriptor) || (containerId == container.second)) - { - return container.first; - } - } - - LOGERR("Failed to find container %s", containerId.c_str()); - return -1; -} - -/** - * @brief Converts the dobbyDescriptor into the OCI Container ID - * - * Will only return a value if Dobby knows about the running container - * (e.g. the container was started by Dobby, not manually using the OCI runtime). - * - * @param Descriptor value - * - * @return containerId The container ID used by the OCI runtime - */ -const std::string DobbyInterface::GetContainerIdFromDescriptor(const int descriptor) -{ - /* Retrieve the list of containers */ - const std::list> containers = mDobbyProxy->listContainers(); - - /* Iterate over the containers to find the one with the matching descriptor */ - for (const std::pair& container : containers) - { - if (container.first == descriptor) - { - /* If the descriptor matches, return the container's ID */ - return container.second; - } - } - - /* If no container is found with the given descriptor, log an error */ - LOGERR("Failed to find container with descriptor %d", descriptor); - return ""; /* Return an empty string to indicate failure */ -} - - -/** - * @brief Callback listener for state change events. - * - * @param descriptor Container descriptor - * @param name Container name - * @param state Container state - * @param _this Callback parameters, or in this case, the pointer to 'this' - */ -const void DobbyInterface::stateListener(int32_t descriptor, const std::string& name, IDobbyProxyEvents::ContainerState state, const void* _this) -{ - // Cast const void* back to DobbyInterface* type to get 'this' - DobbyInterface* __this = const_cast(reinterpret_cast(_this)); - - __this->onContainerStateChanged(descriptor, name, state); - - if (state == IDobbyProxyEvents::ContainerState::Running) - { - __this->onContainerStarted(descriptor, name); - } - else if (state == IDobbyProxyEvents::ContainerState::Stopped) - { - __this->onContainerStopped(descriptor, name); - } - else - { - LOGINFO("Received an unknown state event for container '%s'.", name.c_str()); - } -} - -/** - * @brief Callback listener for OMI error events. - * - * @param id Container id - * @param err Error type - * @param _this Callback parameters, or in this case, the pointer to 'this' - */ -const void DobbyInterface::omiErrorListener(const std::string& id, omi::IOmiProxy::ErrorType err, const void* _this) -{ - - // Cast const void* back to DobbyInterface* type to get 'this' - DobbyInterface* __this = const_cast(reinterpret_cast(_this)); - - if (__this != nullptr && err == omi::IOmiProxy::ErrorType::verityFailed) - { - __this->onVerityFailed(id); - } - else - { - LOGINFO("Received an unknown error type from OMI"); - } -} - -/** - * @brief Handle failure of verity check for container. - * - * @param name Container name. - */ -void DobbyInterface::onVerityFailed(const std::string& name) -{ - LOGINFO("Handle onVerityFailed"); - int cd = GetContainerDescriptorFromId(name); - if (cd < 0) - { - LOGERR("Failed to acquire container descriptor - cannot stop container due to verity failure"); - return; - } - - JsonObject params; - params["descriptor"] = cd; - params["name"] = name; - string containerId = GetContainerIdFromDescriptor(cd); - params["containerId"] = (containerId.empty()) ? name : containerId; - // Set error type to Verity Error (1) - params["errorCode"] = 1; - if (mEventHandler) - { - mEventHandler->onContainerFailed(params); - } - - bool stoppedSuccessfully = mDobbyProxy->stopContainer(cd, true); - - if (!stoppedSuccessfully) - { - LOGERR("Failed to stop container - internal Dobby error."); - return; - } -} - -// End Internal methods - -} // namespace Plugin -} // namespace WPEFramework diff --git a/OCIContainer/DobbyInterface.h b/OCIContainer/DobbyInterface.h deleted file mode 100644 index 1bacc2f..0000000 --- a/OCIContainer/DobbyInterface.h +++ /dev/null @@ -1,79 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "IEventHandler.h" - -namespace WPEFramework -{ -namespace Plugin -{ - class DobbyInterface - { - public: - DobbyInterface(); - virtual ~DobbyInterface(); - DobbyInterface(const DobbyInterface &) = delete; - DobbyInterface &operator=(const DobbyInterface &) = delete; - - bool initialize(IEventHandler* eventHandler); - void terminate(); - - bool listContainers(string& containers, string& errorReason); - bool getContainerInfo(const string& containerId, string& info, string& errorReason); - bool getContainerState(const string& containerId, Exchange::IOCIContainer::ContainerState& state, string& errorReason); - bool startContainer(const string& containerId, const string& bundlePath, const string& command, const string& westerosSocket, int32_t& descriptor, string& errorReason); - bool startContainerFromDobbySpec(const string& containerId, const string& dobbySpec, const string& command, const string& westerosSocket, int32_t& descriptor, string& errorReason); - bool stopContainer(const string& containerId, bool force, string& errorReason); - bool pauseContainer(const string& containerId, string& errorReason); - bool resumeContainer(const string& containerId, string& errorReason); - bool hibernateContainer(const string& containerId, const string& options, string& errorReason); - bool wakeupContainer(const string& containerId, string& errorReason); - bool executeCommand(const string& containerId, const string& options, const string& command, string& errorReason); - bool annotate(const string& containerId, const string& key, const string& value, string& errorReason); - bool removeAnnotation(const string& containerId, const string& key, string& errorReason); - bool mount(const string& containerId, const string& source, const string& target, const string& type, const string& options, string& errorReason); - bool unmount(const string& containerId, const string& target, string& errorReason); - - void onContainerStarted(int32_t descriptor, const std::string& name); - void onContainerStopped(int32_t descriptor, const std::string& name); - void onContainerStateChanged(int32_t descriptor, const std::string& name, IDobbyProxyEvents::ContainerState dobbyContainerState); - void onVerityFailed(const std::string& name); - - private: - int mEventListenerId; // Dobby event listener ID - long unsigned mOmiListenerId; - std::shared_ptr mDobbyProxy; // DobbyProxy instance - std::shared_ptr mIpcService; // Ipc Service instance - const int GetContainerDescriptorFromId(const std::string& containerId); - const std::string GetContainerIdFromDescriptor(const int descriptor); - static const void stateListener(int32_t descriptor, const std::string& name, IDobbyProxyEvents::ContainerState state, const void* _this); - static const void omiErrorListener(const std::string& id, omi::IOmiProxy::ErrorType err, const void* _this); - std::shared_ptr mOmiProxy; - IEventHandler* mEventHandler; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/OCIContainer/IEventHandler.h b/OCIContainer/IEventHandler.h deleted file mode 100644 index 6067c12..0000000 --- a/OCIContainer/IEventHandler.h +++ /dev/null @@ -1,38 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -namespace WPEFramework -{ -namespace Plugin -{ - class IEventHandler - { - public: - virtual void onContainerStarted(JsonObject& data) = 0; - virtual void onContainerStopped(JsonObject& data) = 0; - virtual void onContainerFailed(JsonObject& data) = 0; - virtual void onContainerStateChange(JsonObject& data) = 0; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/OCIContainer/Module.cpp b/OCIContainer/Module.cpp deleted file mode 100644 index cd6d4d1..0000000 --- a/OCIContainer/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/OCIContainer/Module.h b/OCIContainer/Module.h deleted file mode 100644 index 921f482..0000000 --- a/OCIContainer/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_OCIContainer -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/OCIContainer/OCIContainer.conf.in b/OCIContainer/OCIContainer.conf.in deleted file mode 100644 index 10f5744..0000000 --- a/OCIContainer/OCIContainer.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.OCIContainer" -autostart = "true" -startuporder = "@PLUGIN_OCICONTAINER_STARTUPORDER@" diff --git a/OCIContainer/OCIContainer.config b/OCIContainer/OCIContainer.config deleted file mode 100644 index ea3fa70..0000000 --- a/OCIContainer/OCIContainer.config +++ /dev/null @@ -1,7 +0,0 @@ -set (autostart true) -set (preconditions Platform) -set (callsign "org.rdk.OCIContainer") - -if(PLUGIN_OCICONTAINER_STARTUPORDER) -set (startuporder ${PLUGIN_OCICONTAINER_STARTUPORDER}) -endif() diff --git a/OCIContainer/OCIContainer.cpp b/OCIContainer/OCIContainer.cpp deleted file mode 100644 index 035d975..0000000 --- a/OCIContainer/OCIContainer.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "OCIContainer.h" - -const string WPEFramework::Plugin::OCIContainer::SERVICE_NAME = "org.rdk.OCIContainer"; - -namespace WPEFramework -{ - namespace { - - static Plugin::Metadata metadata( - /* Version (Major, Minor, Patch) */ - OCICONTAINER_API_VERSION_NUMBER_MAJOR, OCICONTAINER_API_VERSION_NUMBER_MINOR, OCICONTAINER_API_VERSION_NUMBER_PATCH, - /* Preconditions */ - {}, - /* Terminations */ - {}, - /* Controls */ - {} - ); - } - - namespace Plugin - { - - SERVICE_REGISTRATION(OCIContainer, OCICONTAINER_API_VERSION_NUMBER_MAJOR, OCICONTAINER_API_VERSION_NUMBER_MINOR, OCICONTAINER_API_VERSION_NUMBER_PATCH); - - OCIContainer* OCIContainer::sInstance = nullptr; - - OCIContainer::OCIContainer(): _service(nullptr), mConnectionId(0), mOCIContainerImplementation(nullptr), mOCIContainerNotification(this) - { - SYSLOG(Logging::Startup, (_T("OCIContainer Constructor"))); - OCIContainer::sInstance = this; - } - - OCIContainer::~OCIContainer() - { - SYSLOG(Logging::Startup, (_T("OCIContainer Destructor"))); - OCIContainer::sInstance = nullptr; - mOCIContainerImplementation = nullptr; - } - - const string OCIContainer::Initialize(PluginHost::IShell* service ) - { - //uint32_t result = Core::ERROR_GENERAL; - string retStatus = ""; - ASSERT(nullptr != service); - ASSERT(0 == mConnectionId); - ASSERT(nullptr == _service); - SYSLOG(Logging::Startup, (_T("OCIContainer::Initialize: PID=%u"), getpid())); - //{ - // SYSLOG(Logging::Startup, (_T("OCIContainer::Initialize: service is not valid"))); - // retStatus = _T("OCIContainer plugin could not be initialised"); - //} - _service = service; - _service->AddRef(); - _service->Register(&mOCIContainerNotification); - mOCIContainerImplementation = _service->Root(mConnectionId, 5000, _T("OCIContainerImplementation")); - if(nullptr != mOCIContainerImplementation) - { - // Register for notifications - mOCIContainerImplementation->Register(&mOCIContainerNotification); - // Invoking Plugin API register to wpeframework - Exchange::JOCIContainer::Register(*this, mOCIContainerImplementation); - } - else - { - SYSLOG(Logging::Startup, (_T("OCIContainer::Initialize: Failed to initialise OCIContainer plugin"))); - retStatus = _T("OCIContainer plugin could not be initialised"); - } - - if (0 != retStatus.length()) - { - Deinitialize(service); - } - - return retStatus; - } - - void OCIContainer::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Startup, (_T("OCIContainer::Deinitialize: PID=%u"), getpid())); - ASSERT(_service == service); - if (nullptr != mOCIContainerImplementation) - { - mOCIContainerImplementation->Unregister(&mOCIContainerNotification); - Exchange::JOCIContainer::Unregister(*this); - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mOCIContainerImplementation->Release(); - mOCIContainerImplementation = nullptr; - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - mConnectionId = 0; - if(nullptr != _service) - { - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - _service->Unregister(&mOCIContainerNotification); - _service->Release(); - _service = nullptr; - } - SYSLOG(Logging::Shutdown, (string(_T("OCIContainer de-initialised")))); - } - - string OCIContainer::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - - void OCIContainer::Deactivated(RPC::IRemoteConnection* connection) - { - SYSLOG(Logging::Shutdown, (string(_T("OCIContainer Deactivated")))); - if (connection->Id() == mConnectionId) { - ASSERT(nullptr != _service); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/OCIContainer/OCIContainer.h b/OCIContainer/OCIContainer.h deleted file mode 100644 index 3337def..0000000 --- a/OCIContainer/OCIContainer.h +++ /dev/null @@ -1,133 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework -{ -namespace Plugin -{ - class OCIContainer : public PluginHost::IPlugin, public PluginHost::JSONRPC - { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IOCIContainer::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(OCIContainer* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IOCIContainer::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - LOGINFO("OCIContainer Notification Activated"); - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - LOGINFO("OCIContainer Notification Deactivated"); - _parent.Deactivated(connection); - } - - void OnContainerStarted(const string& containerId, const string& name) override - { - LOGINFO("OnContainerStarted"); - Exchange::JOCIContainer::Event::OnContainerStarted(_parent, containerId, name); - } - - void OnContainerStopped(const string& containerId, const string& name) override - { - LOGINFO("OnContainerStopped"); - Exchange::JOCIContainer::Event::OnContainerStopped(_parent, containerId, name); - } - - void OnContainerFailed(const string& containerId, const string& name, uint32_t error) override - { - LOGINFO("OnContainerFailed"); - Exchange::JOCIContainer::Event::OnContainerFailed(_parent, containerId, name, error); - } - - void OnContainerStateChanged(const string& containerId, Exchange::IOCIContainer::ContainerState state) override - { - LOGINFO("OnContainerStateChanged"); - Exchange::JOCIContainer::Event::OnContainerStateChanged(_parent, containerId, state); - } - - private: - OCIContainer& _parent; - }; - public: - OCIContainer(const OCIContainer&) = delete; - OCIContainer& operator=(const OCIContainer&) = delete; - - OCIContainer(); - virtual ~OCIContainer(); - - BEGIN_INTERFACE_MAP(OCIContainer) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IOCIContainer, mOCIContainerImplementation) - END_INTERFACE_MAP - - /* IPlugin methods */ - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static OCIContainer* sInstance; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: /* members */ - PluginHost::IShell* _service{}; - uint32_t mConnectionId; - Exchange::IOCIContainer* mOCIContainerImplementation; - Core::Sink mOCIContainerNotification; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/OCIContainer/OCIContainerImplementation.cpp b/OCIContainer/OCIContainerImplementation.cpp deleted file mode 100644 index ab24cf4..0000000 --- a/OCIContainer/OCIContainerImplementation.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "OCIContainerImplementation.h" - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(OCIContainerImplementation, 1, 0); - - OCIContainerImplementation::OCIContainerImplementation(): mDobbyInterface(nullptr) - { - LOGINFO("Create OCIContainerImplementation Instance"); - mDobbyInterface = new DobbyInterface(); - mDobbyInterface->initialize(this); - } - - OCIContainerImplementation::~OCIContainerImplementation() - { - LOGINFO("Delete OCIContainerImplementation Instance"); - mDobbyInterface->terminate(); - delete mDobbyInterface; - mDobbyInterface = nullptr; - } - - Core::hresult OCIContainerImplementation::Register(Exchange::IOCIContainer::INotification *notification) - { - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mOCIContainerNotification.begin(), mOCIContainerNotification.end(), notification) == mOCIContainerNotification.end()) - { - LOGINFO("Register notification"); - mOCIContainerNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::Unregister(Exchange::IOCIContainer::INotification *notification) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mOCIContainerNotification.begin(), mOCIContainerNotification.end(), notification); - if (itr != mOCIContainerNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mOCIContainerNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; - } - - void OCIContainerImplementation::dispatchEvent(EventNames event, const JsonObject ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void OCIContainerImplementation::Dispatch(EventNames event, const JsonObject params) - { - //TODO: Convert params to proper values and pass - mAdminLock.Lock(); - string containerId(""); - string name(""); - int state = 0; - uint32_t error = 0; - std::list::const_iterator index(mOCIContainerNotification.begin()); - if(params.HasLabel("containerId")) - { - containerId = params["containerId"].String(); - } - if(params.HasLabel("name")) - { - name = params["name"].String(); - } - if(params.HasLabel("state")) - { - state = params["state"].Number(); - } - if(params.HasLabel("errorCode")) - { - error = params["errorCode"].Number(); - } - switch(event) - { - case OCICONTAINER_EVENT_CONTAINER_STARTED: - while (index != mOCIContainerNotification.end()) - { - if (*index != nullptr) { - (*index)->OnContainerStarted(containerId, name); - } - ++index; - } - break; - case OCICONTAINER_EVENT_CONTAINER_STOPPED: - while (index != mOCIContainerNotification.end()) - { - if (*index != nullptr) { - (*index)->OnContainerStopped(containerId, name); - } - ++index; - } - break; - case OCICONTAINER_EVENT_CONTAINER_FAILED: - while (index != mOCIContainerNotification.end()) - { - if (*index != nullptr) { - (*index)->OnContainerFailed(containerId, name, error); - } - ++index; - } - break; - case OCICONTAINER_EVENT_STATE_CHANGED: - while (index != mOCIContainerNotification.end()) - { - if (*index != nullptr) { - ContainerState containerState = static_cast(state); - (*index)->OnContainerStateChanged(containerId, containerState); - } - ++index; - } - break; - - default: - LOGWARN("Event[%u] not handled", event); - break; - } - - mAdminLock.Unlock(); - } - - - Core::hresult OCIContainerImplementation::ListContainers(string& containers, bool& success, string& errorReason) - { - success = mDobbyInterface->listContainers(containers, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::GetContainerInfo(const string& containerId, string& info, bool& success, string& errorReason) - { - success = mDobbyInterface->getContainerInfo(containerId, info, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::GetContainerState(const string& containerId, ContainerState& state, bool& success, string& errorReason) - { - success = mDobbyInterface->getContainerState(containerId, state, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::StartContainer(const string& containerId, const string& bundlePath, const string& command, const string& westerosSocket, int32_t& descriptor, bool& success, string& errorReason) - { - success = mDobbyInterface->startContainer(containerId, bundlePath, command, westerosSocket, descriptor, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::StartContainerFromDobbySpec(const string& containerId, const string& dobbySpec, const string& command, const string& westerosSocket, int32_t& descriptor, bool& success, string& errorReason) - { - success = mDobbyInterface->startContainerFromDobbySpec(containerId, dobbySpec, command, westerosSocket, descriptor, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::StopContainer(const string& containerId, bool force, bool& success, string& errorReason) - { - success = mDobbyInterface->stopContainer(containerId, force, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::PauseContainer(const string& containerId, bool& success, string& errorReason) - { - success = mDobbyInterface->pauseContainer(containerId, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::ResumeContainer(const string& containerId, bool& success, string& errorReason) - { - success = mDobbyInterface->resumeContainer(containerId, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::HibernateContainer(const string& containerId, const string& options, bool& success, string& errorReason) - { - success = mDobbyInterface->hibernateContainer(containerId, options, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::WakeupContainer(const string& containerId, bool& success, string& errorReason) - { - success = mDobbyInterface->wakeupContainer(containerId, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::ExecuteCommand(const string& containerId, const string& options, const string& command, bool& success ,string& errorReason) - { - success = mDobbyInterface->executeCommand(containerId, options, command, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::Annotate(const string& containerId, const string& key, const string& value, bool& success, string& errorReason) - { - success = mDobbyInterface->annotate(containerId, key, value, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::RemoveAnnotation(const string& containerId, const string& key, bool& success, string& errorReason) - { - success = mDobbyInterface->removeAnnotation(containerId, key, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::Mount(const string& containerId, const string& source, const string& target, const string& type, const string& options, bool& success ,string& errorReason) - { - success = mDobbyInterface->mount(containerId, source, target, type, options, errorReason); - - return Core::ERROR_NONE; - } - - Core::hresult OCIContainerImplementation::Unmount(const string& containerId, const string& target, bool& success, string& errorReason) - { - success = mDobbyInterface->unmount(containerId, target, errorReason); - - return Core::ERROR_NONE; - } - - void OCIContainerImplementation::onContainerStarted(JsonObject& data) - { - dispatchEvent(OCIContainerImplementation::EventNames::OCICONTAINER_EVENT_CONTAINER_STARTED, data); - } - - void OCIContainerImplementation::onContainerStopped(JsonObject& data) - { - dispatchEvent(OCIContainerImplementation::EventNames::OCICONTAINER_EVENT_CONTAINER_STOPPED, data); - } - - void OCIContainerImplementation::onContainerFailed(JsonObject& data) - { - dispatchEvent(OCIContainerImplementation::EventNames::OCICONTAINER_EVENT_CONTAINER_FAILED, data); - } - - void OCIContainerImplementation::onContainerStateChange(JsonObject& data) - { - dispatchEvent(OCIContainerImplementation::EventNames::OCICONTAINER_EVENT_STATE_CHANGED, data); - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/OCIContainer/OCIContainerImplementation.h b/OCIContainer/OCIContainerImplementation.h deleted file mode 100644 index 4749854..0000000 --- a/OCIContainer/OCIContainerImplementation.h +++ /dev/null @@ -1,135 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include "DobbyInterface.h" -#include "IEventHandler.h" - -namespace WPEFramework -{ -namespace Plugin -{ - class OCIContainerImplementation : public Exchange::IOCIContainer, public IEventHandler - { - public: - enum EventNames - { - OCICONTAINER_EVENT_CONTAINER_STARTED, - OCICONTAINER_EVENT_CONTAINER_STOPPED, - OCICONTAINER_EVENT_CONTAINER_FAILED, - OCICONTAINER_EVENT_STATE_CHANGED - }; - class EXTERNAL Job : public Core::IDispatch - { - protected: - Job(OCIContainerImplementation *runtimeManagerImplementation, EventNames event, JsonObject ¶ms) - : mOCIContainerImplementation(runtimeManagerImplementation) - , _event(event) - , _params(params) - { - if (mOCIContainerImplementation != nullptr) - { - mOCIContainerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() - { - if (mOCIContainerImplementation != nullptr) - { - mOCIContainerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(OCIContainerImplementation *runtimeManagerImplementation, EventNames event, JsonObject params) - { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(runtimeManagerImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(runtimeManagerImplementation, event, params))); -#endif - } - - virtual void Dispatch() - { - mOCIContainerImplementation->Dispatch(_event, _params); - } - private: - OCIContainerImplementation *mOCIContainerImplementation; - const EventNames _event; - const JsonObject _params; - }; - - OCIContainerImplementation (); - ~OCIContainerImplementation () override; - OCIContainerImplementation (const OCIContainerImplementation &) = delete; - OCIContainerImplementation & operator=(const OCIContainerImplementation &) = delete; - - BEGIN_INTERFACE_MAP(OCIContainerImplementation) - INTERFACE_ENTRY(Exchange::IOCIContainer) - END_INTERFACE_MAP - - /* IOCIContainer methods */ - virtual Core::hresult Register(Exchange::IOCIContainer::INotification *notification) override; - virtual Core::hresult Unregister(Exchange::IOCIContainer::INotification *notification) override; - virtual Core::hresult ListContainers(string& containers, bool& success, string& errorReason) override; - virtual Core::hresult GetContainerInfo(const string& containerId, string& info, bool& success, string& errorReason) override; - virtual Core::hresult GetContainerState(const string& containerId, ContainerState& state, bool& success, string& errorReason) override; - virtual Core::hresult StartContainer(const string& containerId, const string& bundlePath, const string& command, const string& westerosSocket, int32_t& descriptor, bool& success, string& errorReason) override; - virtual Core::hresult StartContainerFromDobbySpec(const string& containerId, const string& dobbySpec, const string& command, const string& westerosSocket, int32_t& descriptor, bool& success, string& errorReason) override; - virtual Core::hresult StopContainer(const string& containerId, bool force, bool& success, string& errorReason) override; - virtual Core::hresult PauseContainer(const string& containerId, bool& success, string& errorReason) override; - virtual Core::hresult ResumeContainer(const string& containerId, bool& success, string& errorReason) override; - virtual Core::hresult HibernateContainer(const string& containerId, const string& options, bool& success, string& errorReason) override; - virtual Core::hresult WakeupContainer(const string& containerId, bool& success, string& errorReason) override; - virtual Core::hresult ExecuteCommand(const string& containerId, const string& options, const string& command, bool& success ,string& errorReason) override; - virtual Core::hresult Annotate(const string& containerId, const string& key, const string& value, bool& success, string& errorReason) override; - virtual Core::hresult RemoveAnnotation(const string& containerId, const string& key, bool& success, string& errorReason) override; - virtual Core::hresult Mount(const string& containerId, const string& source, const string& target, const string& type, const string& options, bool& success ,string& errorReason) override; - virtual Core::hresult Unmount(const string& containerId, const string& target, bool& success, string& errorReason) override; - - virtual void onContainerStarted(JsonObject& data) override; - virtual void onContainerStopped(JsonObject& data) override; - virtual void onContainerFailed(JsonObject& data) override; - virtual void onContainerStateChange(JsonObject& data) override; - - private: /* members */ - mutable Core::CriticalSection mAdminLock; - std::list mOCIContainerNotification; - DobbyInterface* mDobbyInterface; - - private: /* internal methods */ - void dispatchEvent(EventNames, const JsonObject ¶ms); - void Dispatch(EventNames event, const JsonObject params); - - friend class Job; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/OCIContainer/README.md b/OCIContainer/README.md deleted file mode 100644 index 2160356..0000000 --- a/OCIContainer/README.md +++ /dev/null @@ -1,359 +0,0 @@ -# OCI Container Manager (Dobby) Thunder Plugin - -This Thunder plugin allows for control of OCI containers using the Dobby hypervisor. - -It interfaces with Dobby over the existing dbus API - -# APIs -## listContainers -List all running OCI containers Dobby knows about -### Parameters -None -### Result -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "containers":[ - { - "Descriptor":91, - "Id":"com.bskyb.epgui" - } - ], - "success":true - } -} -``` - -## getContainerState -Get the state of a currently running container. Possible states include: -* Invalid -* Starting -* Running -* Stopped -* Paused - -### Params -| Name | Type | Description | -| ----------- | ------ | --------------------------------------- | -| containerId | string | ID of the container to get the state of | - -### Result -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "containerId":"com.bskyb.epgui", - "state":"Running", - "success":true - } -} -``` - ---- - -## getContainerInfo - -Gets information about a running container such as CPU, memory and GPU uage (GPU not supported on some products) -======= - - -### Params -| Name | Type | Description | -| ----------- | ------ | -------------------------------------------- | -| containerId | string | ID of the container to get information about | - -### Result -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "info":{ - "cpu":{ - "usage":{ - "percpu":[ - 83134464184, - 95791749503, - 31057322312, - 14041572680 - ], - "total":224025108679 - } - }, - "id":"com.bskyb.epgui", - "memory":{ - "user":{ - "failcnt":0, - "limit":230686720, - "max":38555648, - "usage":28655616 - } - }, - "pids":[ - 7644, - 7736 - ], - "state":"running", - "timestamp":6849968158125 - }, - "success":true - } -} -``` ---- -## startContainer - -Starts a new container from an existing OCI bundle. - -### Params -| Name | Type | Description | -| -------------- | ------ | ------------------------------------------------------------------------------------------ | -| containerId | string | ID for the new container | -| bundlePath | string | Path to the OCI bundle containing the rootfs and config to use to create the container | -| command | string | Custom command to run inside the container, overriding the command in the container config | -| westerosSocket | string | Path to a westeros socket to mount inside the container | ---- - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "descriptor":257, - "success":true - } -} -``` - -## startContainerFromDobbySpec - -Starts a new container from a legacy Dobby json specification - -### Params -| Name | Type | Description | -| ----------- | ------ | ------------------------------------------------------------------------------------ | -| containerId | string | ID for the new container | -| dobbySpec | object | Dobby specification to use for the container | -| command | string | Custom command to run inside the container, overriding the command in the Dobby spec | - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "descriptor":257, - "success":true - } -} -``` ---- -## stopContainer -Stop a currently running container - -### Params -| Name | Type | Description | -| ----------- | ------- | ----------------------------------------------------------------------------------------------------- | -| containerId | string | ID of the container to stop | -| force | boolean | [Optional - defaults to false] If true, force stop the container (SIGKILL). Otherwise SIGTERM is used | - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "success":true - } -} -``` ---- -## execCommamd - -Execute a command inside a running container. The path to the executable must resolve within the container's namespace. - -### Params -| Name | Type | Description | -| ----------- | ------ | ----------------------------------------- | -| containerId | string | ID of the container to run the command in | -| options | string | Global options for crun's exec command | -| command | string | Command to execute | - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "success":true - } -} -``` - ---- -## deleteContainer -**NOT YET IMPLEMENTED** - -Delete a container bundle - -### Params -**TODO:: Decide on parameters** - -### Response -**NOT YET IMPLEMENTED** - ---- -## pauseContainer - -Pause a currently running container - -### Params -| Name | Type | Description | -| ----------- | ------ | ---------------------------- | -| containerId | string | ID of the container to pause | - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "success":true - } -} -``` ---- -## resumeContainer - -Resume a previously paused container - -### Params -| Name | Type | Description | -| ----------- | ------ | ----------------------------------------------------------------- | -| containerId | string | ID of the container to resume (must already be in a paused state) | - -### Response -```json -{ - "jsonrpc":"2.0", - "id":3, - "result":{ - "success":true - } -} -``` ---- ---- -# Build -``` -bitbake thunder-plugins -``` - -# Test -Sample curl commands to use to test the API - -**ListContainers** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.listContainers"}' - -``` - -**Get State** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.getContainerState", "params": {"containerId": "SleepTest"}}' -``` - -**Get Info** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.getContainerInfo", "params": {"containerId": "SleepTest"}}' -``` - -**Start (Bundle path)** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{ - "jsonrpc":"2.0", - "id":3, - "method":"org.rdk.OCIContainer.1.startContainer", - "params":{ - "containerId": "SleepTest", - "bundlePath": "[-INSERT BUNDLE PATH-]" - } -}' -``` - -**Start (Dobby Spec)** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{ - "jsonrpc":"2.0", - "id":3, - "method":"org.rdk.OCIContainer.1.startContainerFromDobbySpec", - "params":{ - "containerId": "SleepTest", - "dobbySpec":{ - "version": "1.0", - "cwd": "/", - "args": [ - "sleep", - "60" - ], - "env": [ - - ], - "user": { - "uid": 1000, - "gid": 1000 - }, - "console": { - "limit": 65536, - "path": "/tmp/container.log" - }, - "etc": { - "group": [ - "root:x:0:" - ], - "passwd": [ - "root::0:0:root:/:/bin/false" - ] - }, - "memLimit": 41943040, - "network": "nat", - "mounts": [ - - ] - } - } -}' -``` - -**Stop Container** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.stopContainer", "params": {"containerId": "SleepTest"}}' -``` - -**Pause Container** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.pauseContainer", "params": {"containerId": "SleepTest"}}' -``` - -**Resume Container** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{"jsonrpc": "2.0", "id": 3, "method": "org.rdk.OCIContainer.1.resumeContainer", "params": {"containerId": "SleepTest"}}' -``` - -**Execute Command** -``` -curl -X POST http://127.0.0.1:9998/jsonrpc/ -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "org.rdk.OCIContainer.1.executeCommand", - "params": { - "containerId": "SleepTest", - "options": "", - "command": "ls" - } -}' -``` diff --git a/OCIContainer/stubs/i_omi_proxy.hpp b/OCIContainer/stubs/i_omi_proxy.hpp deleted file mode 100644 index 365fb0e..0000000 --- a/OCIContainer/stubs/i_omi_proxy.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2021 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef I_OMI_PROXY_HPP_ -#define I_OMI_PROXY_HPP_ - -#include -#include - -namespace omi -{ - -/** - * @interface IOmiProxy - * @brief Wrapper around an omi_dbus_api that provides simpler method - * calls and give possibility to register/unregister for incoming signals. - */ -class IOmiProxy -{ -public: - enum class ErrorType { verityFailed }; - - typedef std::function OmiErrorListener; - - // Mount crypted bundle - // id [IN] - Container ID in reverse domain name notation - // rootfs_file_path [IN] - Absolute pathname for filesystem image - // config_json_path [IN] - Absolute pathname for config.json.jwt - // bundlePath [OUT] - Absolute pathname for decrypted config.json payload - // Returns TRUE on success, FALSE on error - virtual bool mountCryptedBundle(const std::string& id, - const std::string& rootfs_file_path, - const std::string& config_json_path, - std::string& bundlePath /*out parameter*/) = 0; - - // Unmount crypted bundle - // id [IN] - Container ID in reverse domain name notation - // Returns TRUE on success, FALSE on error - virtual bool umountCryptedBundle(const std::string& id) = 0; - - // Register listener - // listener [IN] - OMI error listener which will be called on error event occurrence - // Returns listener ID (0<) or 0 on error - virtual long unsigned registerListener(const OmiErrorListener &listener, const void* cbParams) = 0; - - // Unregister listener - // tag [IN] - ID which defines listener to be unregistered - virtual void unregisterListener(long unsigned tag) = 0; - -}; -} // namespace omi -#endif // #ifndef I_OMI_PROXY_HPP_ diff --git a/OCIContainer/stubs/omi_proxy.hpp b/OCIContainer/stubs/omi_proxy.hpp deleted file mode 100644 index b5f99b5..0000000 --- a/OCIContainer/stubs/omi_proxy.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2021 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef OMI_PROXY_HPP_ -#define OMI_PROXY_HPP_ - -#include - -namespace omi -{ - -class OmiProxy : public IOmiProxy -{ -public: - OmiProxy() = default; - virtual ~OmiProxy() = default; - - virtual bool mountCryptedBundle(const std::string& id, - const std::string& rootfs_file_path, - const std::string& config_json_path, - std::string& bundlePath) { return true; } - - virtual bool umountCryptedBundle(const std::string& id) { return true; } - - virtual long unsigned registerListener(const OmiErrorListener &listener, const void* cbParams) { return 0; } - - virtual void unregisterListener(long unsigned tag) {} -}; - -} // namespace omi - -#endif // OMI_PROXY_HPP_ diff --git a/OCIContainer/test/DobbySpecs/helloworld.json b/OCIContainer/test/DobbySpecs/helloworld.json deleted file mode 100644 index 6ce2b30..0000000 --- a/OCIContainer/test/DobbySpecs/helloworld.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": "1.0", - "cwd": "/", - "args": [ - "echo", - "Hello World" - ], - "env": [ - - ], - "user": { - "uid": 1000, - "gid": 1000 - }, - "console": { - "limit": 65536, - "path": "/tmp/echo.log" - }, - "etc": { - "group": [ - "root:x:0:" - ], - "passwd": [ - "root::0:0:root:/:/bin/false" - ] - }, - "memLimit": 41943040, - "network": "nat", - "mounts": [ - - ] -} \ No newline at end of file diff --git a/OCIContainer/test/DobbySpecs/sleepy.json b/OCIContainer/test/DobbySpecs/sleepy.json deleted file mode 100644 index ea1f7bb..0000000 --- a/OCIContainer/test/DobbySpecs/sleepy.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": "1.0", - "cwd": "/", - "args": [ - "sleep", - "60" - ], - "env": [ - - ], - "user": { - "uid": 1000, - "gid": 1000 - }, - "console": { - "limit": 65536, - "path": "/tmp/container.log" - }, - "etc": { - "group": [ - "root:x:0:" - ], - "passwd": [ - "root::0:0:root:/:/bin/false" - ] - }, - "memLimit": 41943040, - "network": "nat", - "mounts": [ - - ] -} \ No newline at end of file diff --git a/OCIContainer/test/DobbySpecs/wget.json b/OCIContainer/test/DobbySpecs/wget.json deleted file mode 100644 index 24af396..0000000 --- a/OCIContainer/test/DobbySpecs/wget.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "version": "1.0", - "cwd": "/", - "args": [ - "wget", - "example.com" - ], - "env": [ - - ], - "user": { - "uid": 1000, - "gid": 1000 - }, - "console": { - "limit": 65536, - "path": "/tmp/wget.log" - }, - "etc": { - "group": [ - "root:x:0:" - ], - "passwd": [ - "root::0:0:root:/:/bin/false" - ] - }, - "memLimit": 41943040, - "network": "nat", - "mounts": [{ - "destination": "/etc/resolv.conf", - "type": "bind", - "source": "/etc/resolv.conf", - "options": [ - "ro", - "rbind", - "rprivate", - "nosuid", - "noexec", - "nodev" - ] - }] -} \ No newline at end of file diff --git a/OCIContainer/test/ociContainerTest.sh b/OCIContainer/test/ociContainerTest.sh deleted file mode 100755 index 6d4c10c..0000000 --- a/OCIContainer/test/ociContainerTest.sh +++ /dev/null @@ -1,338 +0,0 @@ -#!/bin/bash - -### -# If not stated otherwise in this file or this component's LICENSE -# file the following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -### - -testdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -url="http://127.0.0.1:9998/Service/" -curl_opts="--silent -X POST ${url} --header \"Content-Type: application/json\"" -container_id="TestContainer" - -bundlesdir="${testdir}/TestBundles/" -specsdir="${testdir}/DobbySpecs/" - -# Start container with OCI bundle from ./TestBundles directory -start_container_from_bundle() -{ - echo "" - # Check if path to bundle or bundle name - if grep -q "/" <<< "$1"; then - container_id="$(echo ${1} | sed 's/.*\///')" - bundle_path="${1}" - else - container_id="${1}" - bundle_path="${bundlesdir}${1}" - bundle_tarball="${bundlesdir}${1}.tar.gz" - - # Extract tarball if it hasn't already been extracted - if [ ! -d "${bundle_path}" ] && [ -f "${bundle_tarball}" ]; then - tar -xzf "${bundle_tarball}" -C "${bundlesdir}" - fi - fi - - if [ -d "${bundle_path}" ]; then - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.startContainer", - "params":{ - "containerId": "'${container_id}'", - "bundlePath": "'${bundle_path}'" - } - }') - echo ${response} - else - echo "ERROR: bundle not found in ${bundle_path}/" - fi - echo "" -} - -# Start container with Dobby spec from ./DobbySpecs directory -start_container_from_spec() -{ - echo "" - dobby_spec="${specsdir}/${1}.json" - - if [ -f "${dobby_spec}" ]; then - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.startContainerFromDobbySpec", - "params":{ - "containerId": "'${1}'", - "dobbySpec": '"$(<${dobby_spec})"' - } - }') - echo ${response} - else - echo "ERROR: Dobby spec '${1}.json' not found in ${specsdir}/" - fi - echo "" -} - -# Stop a running container -stop_container() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.stopContainer", - "params":{ - "containerId": "'${1}'" - } - }') - - echo ${response} - echo "" -} - -# List all running containers -list_containers() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.listContainers" - }') - - echo ${response} - echo "" -} - -# Get a container's info -get_container_info() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.getContainerInfo", - "params":{ - "containerId": "'${1}'" - } - }') - - echo ${response} - echo "" -} - -# Get a container's state -get_container_state() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.getContainerState", - "params":{ - "containerId": "'${1}'" - } - }') - - echo ${response} - echo "" -} - -# Pause a container -pause_container() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.pauseContainer", - "params":{ - "containerId": "'${1}'" - } - }') - - echo ${response} - echo "" -} - -# Resume a paused container -resume_container() -{ - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.resumeContainer", - "params":{ - "containerId": "'${1}'" - } - }') - - echo ${response} - echo "" -} - -# Run the executeCommand method with input params -execute_command() -{ - args=("$@") - options="" - command="" - options_empty="" - - # Move options and command into their respective strings - for i in "${args[@]:1:${#args[@]}}"; do # args from args[1] (=containerId) until the end of the array - if [[ $i == -* && -z "$options_empty" ]]; then - options="$options$i " - else - options_empty="1" - command="$command$i " - fi - done - - # Remove trailing spaces - options=$(sed 's/ *$//g' <<< $options) - command=$(sed 's/ *$//g' <<< $command) - - echo "" - response=$(curl ${curl_opts} -d '{ - "jsonrpc": "2.0", - "id": 3, - "method": "OCIContainer.1.executeCommand", - "params":{ - "containerId": "'${1}'", - "options": "'"${options}"'", - "command": "'"${command}"'" - } - }') - - echo ${response} - echo "" -} - -# Available commands -ocicontainer_help() -{ - echo "" - echo "" - echo "Commands:" - echo "" - echo "s - start container from an OCI bundle in ./TestBundles or from given path." - echo "ss - start container from a dobby spec in ./DobbySpecs." - echo "t - stop container." - echo "l - list containers." - echo "i - get container info." - echo "g - get container state." - echo "p - pause container." - echo "r - resume paused container." - echo "e [options...] - execute a command in container." - echo "h - help." - echo "x - exit the script." - echo "" -} - -main() -{ - # Read user input and create an args array out of it - read -p "Command:" input - read -a args <<< ${input} - - case ${args[0]} in - s) - if [ ${args[1]} ]; then - start_container_from_bundle ${args[1]} - else - echo "ERROR: Missing arguments. Try 's .'" - echo "" - fi - ;; - ss) - if [ ${args[1]} ]; then - start_container_from_spec ${args[1]} - else - echo "ERROR: Missing arguments. Try 'ss .'" - echo "" - fi - ;; - t) - if [ ${args[1]} ]; then - stop_container ${args[1]} - else - echo "ERROR: Missing arguments. Try 't .'" - echo "" - fi - ;; - l) - list_containers ;; - i) - if [ ${args[1]} ]; then - get_container_info ${args[1]} - else - echo "ERROR: Missing arguments. Try 'i .'" - echo "" - fi - ;; - g) - if [ ${args[1]} ]; then - get_container_state ${args[1]} - else - echo "ERROR: Missing arguments. Try 'g .'" - echo "" - fi - ;; - p) - if [ ${args[1]} ]; then - pause_container ${args[1]} - else - echo "ERROR: Missing arguments. Try 'p .'" - echo "" - fi - ;; - - r) - if [ ${args[1]} ]; then - resume_container ${args[1]} - else - echo "ERROR: Missing arguments. Try 'r .'" - echo "" - fi - ;; - e) - if [[ (${args[1]} && ${args[2]}) ]]; then - execute_command ${args[@]:1:${#args[@]}} # args from args[1] until the end of the array - else - echo "ERROR: Missing arguments. Try 'e [options...] .'" - echo "" - fi - ;; - h) - ocicontainer_help ;; - x) - exit ;; - X) - exit ;; - *) - echo "Invalid selection." - echo "" - ;; - esac - main -} - -echo "OCIContainer test tool" -echo "------------------------" -ocicontainer_help -main diff --git a/OCIContainer/test/thunder-ocicontainer-test.js b/OCIContainer/test/thunder-ocicontainer-test.js deleted file mode 100644 index e68219f..0000000 --- a/OCIContainer/test/thunder-ocicontainer-test.js +++ /dev/null @@ -1,364 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Thunder Plugin OCIContainer test - * - * author: Justin Ware - * author: Antti Kyllonen - */ - -'use strict'; - -const startTime = new Date().valueOf(); -function log(message) { console.log(((new Date().valueOf() - startTime) / 1000).toFixed(3) + ' ' + message); } - -px.import({ - scene:'px:scene.1.js', - ws: 'ws' - }).then( function ready(imported) { - const WebSocket = imported.ws; - - let ws; - let wsResps = []; - - const connect = () => { - return new Promise( (resolve, reject) => { - ws = new WebSocket('ws://localhost:9998/jsonrpc', 'notification'); - ws.onopen = () => { resolve(ws); }; - ws.onerror = error => { reject(error); }; - ws.onmessage = e => { wsResps.push(e.data); } - }); - }; - - let responseId = 0; - let pluginName = ''; - let pluginVersion = ''; - let containerName = ''; - let testDobbySpec = ''; - const responseTimeout = 10000; - const checkPeriod = 500; - // How many tests passed and failed - let testResults = { - passed_: 0, - failed_: 0, - - /** - * A test has passed. - */ - passed: function() { - ++this.passed_; - }, - - /** - * A test has failed. - * - * @param reason The reason why. - */ - failed: function(reason) { - ++this.failed_; - - log('FAILED: ' + reason); - }, - - /** - * Test if something is true. - * - * @param check If true then the test has passed. - * @param description A description of the test. - */ - isTrue: function(check, description) { - if (check) - this.passed(); - else - this.failed(description); - }, - - /** - * Report the results. - */ - report: function() { - if (this.failed_ === 0) - log('Test Results: all ' + this.passed_ + ' tests passed'); - else - log('Test Results: ' + this.passed_ + ' passed; ' + this.failed_ + ' failed'); - } - }; - - /** - * Invoke a method and process response. - * - * @param {*} method The name of the method. - * @param {*} params Any parameters as object of names and values. - * @param {*} timeout Optional timeout to wait for response (defaults to 10s). - * @param {*} check Optional function used to check response. - */ - const invoke = (method, params, timeout, check) => { - return new Promise( (resolve, reject) => { - const cmd = JSON.stringify({ jsonrpc: '2.0', id: ++responseId, method: pluginName + '.' + pluginVersion + '.' + method, params: params === undefined ? {} : params } ); - ws.send(cmd); - log('\trequest: ' + cmd); - - let interval; - const checkInputResponses = () => { - for (let i = 0; i < wsResps.length; i++) { - const e = wsResps[i]; - const resp = JSON.parse(e); - if (resp.id !== undefined && resp.id === responseId) { - log('\tresponse: ' + e); - if (interval !== undefined) clearInterval(interval); - wsResps.splice(i, 1); - - if (check !== undefined) - check(resp.result); - resolve(); - } - } - }; - if (timeout === undefined) timeout = responseTimeout; - checkInputResponses(); - interval = setInterval(() => { - checkInputResponses(); - timeout -= checkPeriod; - if (timeout <= 0) { - clearInterval(interval); - testResults.failed('\ttimeout for request: \'' + method + '\''); - reject(); - } - }, checkPeriod); - }); - }; - - /** - * Wait for an event from Thunder. - * - * @param {*} name The name of the event. - * @param {*} id The id of the request associated with the event. - * @param {*} timeout An optional timeout to override the default one. - * @param {*} check Optional function used to check event. Return true if more events in this sequence are expected. - */ - const waitEvent = (name, id, timeout, check) => { - return new Promise( (resolve, reject) => { - log('\twaitEvent \'' + id + '.' + name + '\' start'); - - // Returns true if the response has been found - const checkInputResponses = () => { - for (let i = 0; i < wsResps.length; i++) { - const resp = JSON.parse(wsResps[i]); - if (resp.method !== undefined && resp.method === id + '.' + name) { - log('\twaitEvent \'' + id + '.' + name + '\' received: ' + JSON.stringify(resp.params)); - wsResps.splice(i, 1); - - // Is the response to be checked? - let finished = true; - if (check !== undefined) { - // By returning true it implies that more events of this time are expected - let moreData = check(resp.params) - if ((moreData !== undefined) && (moreData === true)) - { - finished = false; - log('\twaitEvent expecting more results...'); - } - } - - if (finished) { - resolve(resp); - return true; - } - } - } - - // Haven't found the event - return false; - }; - if (timeout === undefined) timeout = responseTimeout; - if (checkInputResponses()) - return; - let interval = setInterval(() => { - // Have we found the response? - if (checkInputResponses()) { - clearInterval(interval); - return; - } - - // Have we timed out? - timeout -= checkPeriod; - if (timeout <= 0) { - clearInterval(interval); - testResults.failed('\twaitEvent \'' + id + '.' + name + '\' timeout'); - reject(); - } - }, checkPeriod); - }); - }; - - pluginName = 'org.rdk.OCIContainer'; // Change to 'OCIContainer' if running outside RDK builds - pluginVersion = '1'; - containerName = 'sleepy'; - testDobbySpec = { - "version": "1.0", - "cwd": "/", - "args": [ - "sleep", - "30" - ], - "env": [ - - ], - "user": { - "uid": 1000, - "gid": 1000 - }, - "console": { - "limit": 65536, - "path": "/tmp/container.log" - }, - "etc": { - "group": [ - "root:x:0:" - ], - "passwd": [ - "root::0:0:root:/:/bin/false" - ] - }, - "memLimit": 41943040, - "network": "nat", - "mounts": [ - - ] - }; - - // Run the tests. - connect() - .catch( error => { log('web socket can\'t be opened: ' + error);}) - .then( () => { - log("Register 'onContainerStarted' notification listener."); - return invoke('register', { event: 'onContainerStarted', id: 1}, undefined, (result) => { - testResults.isTrue(result === 0, 'Expected to succeed'); - }); - }) - .then( () => { - log("Register 'onContainerStopped' notification listener."); - return invoke('register', { event: 'onContainerStopped', id: 2}, undefined, (result) => { - testResults.isTrue(result === 0, 'Expected to succeed'); - }); - }) - .then( () => { - log("Starting container '" + containerName + "' from a Dobby Spec."); - return invoke('startContainerFromDobbySpec', {containerId: containerName, dobbySpec: testDobbySpec}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Wait for 'onContainerStarted' notification."); - return waitEvent('onContainerStarted', 1, undefined, (params) => { - testResults.isTrue(('descriptor' in params) && (params.name === containerName), - "Expected 'params.name' to be " + containerName); - }); - }) - .then( () => { - log("List containers."); - return invoke('listContainers', {}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Get info of container '" + containerName + "'."); - return invoke('getContainerInfo', {containerId: containerName}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Pause the container '" + containerName + "'."); - return invoke('pauseContainer', {containerId: containerName}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Check container " + containerName + " state to make sure it's paused."); - return invoke('getContainerState', {containerId: containerName}, undefined, (params) => { - testResults.isTrue(('containerId' in params) && (params.state === "Paused"), "Expected 'params.state' to be 'Paused'"); - }); - }) - .then( () => { - log("Resume the container '" + containerName + "'."); - return invoke('resumeContainer', {containerId: containerName}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Check container " + containerName + " to make sure it's running again."); - return invoke('getContainerState', {containerId: containerName}, undefined, (params) => { - testResults.isTrue(('containerId' in params) && (params.state === "Running"), "Expected 'params.state' to be 'Running'"); - }); - }) - .then( () => { - log("Execute 'ls' in container '" + containerName + "'."); - return invoke('executeCommand', {containerId: containerName, options: "", command: "ls"}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Stop the container '" + containerName + "'."); - return invoke('stopContainer', {containerId: containerName, force: "false"}, undefined, (result) => { - testResults.isTrue(result.success, 'Expected to succeed'); - }); - }) - .then( () => { - log("Wait for 'onContainerStopped' notification."); - return waitEvent('onContainerStopped', 2, undefined, (params) => { - testResults.isTrue(('descriptor' in params) && (params.name === containerName), - "Expected 'params.name' to be " + containerName); - }); - }) - .then( () => { - log("Unregister 'onContainerStarted' notification listener."); - return invoke('unregister', { event: 'onContainerStarted', id: 1}, undefined, (result) => { - testResults.isTrue(result === 0, 'Expected to succeed'); - }); - }) - .then( () => { - log("Unregister 'onContainerStopped' notification listener."); - return invoke('unregister', { event: 'onContainerStopped', id: 2}, undefined, (result) => { - testResults.isTrue(result === 0, 'Expected to succeed'); - }); - }) - .then( () => { - // There shouldn't be any unhandled responses / events - return new Promise((resolve) => { - let unhandledCount = 0; - for (const resp of wsResps) { - let respObj = JSON.parse(resp); - - if (unhandledCount === 0) - log('Remaining responses / events'); - log(' ' + resp); - ++unhandledCount; - } - - testResults.isTrue(unhandledCount === 0, - "Expected not to have unhandled responses / events."); - resolve(); - }); - }) - .then( () => { - testResults.report(); - // TODO - need to close Spark - }); -}).catch( err => { console.error('Import failed: ' + err); }); diff --git a/PRODUCT.md b/PRODUCT.md new file mode 100644 index 0000000..2c04f99 --- /dev/null +++ b/PRODUCT.md @@ -0,0 +1,167 @@ +# UserSettings Plugin - Product Overview + +## Product Functionality + +The UserSettings plugin provides a unified, persistent user preferences management system for RDK-based devices. It enables applications and services to store, retrieve, and synchronize user-configurable settings across the entire platform, ensuring a consistent user experience regardless of which application or service accesses the settings. + +### Core Features + +#### Comprehensive Settings Management +The plugin manages a complete spectrum of user preferences across five key categories: + +1. **Audio Preferences** + - Enable/disable audio description for visually impaired users + - Configure preferred audio language priorities for multi-language content + +2. **Caption and Subtitle Control** + - Toggle closed captions on/off + - Set preferred caption language priorities + - Select closed caption service type (CC1-CC4, AUTO) + +3. **Parental Controls** + - PIN-based content access control + - Age-based viewing restrictions (G, PG, PG-13, R, NC-17, etc.) + - Time-window restrictions for content access + - Watershed hour enforcement for live and recorded content + - Block unrated content + - Purchase protection with PIN + - Configurable content PIN codes + +4. **Accessibility Features** + - System presentation language selection + - High contrast display mode for enhanced visibility + - Voice guidance for visually impaired navigation + - Adjustable voice guidance speech rate (0.1x to 10x) + - Voice guidance hints and prompts + +5. **Privacy Settings** + - Privacy mode configuration for data collection preferences + +#### Real-Time Synchronization +- Event-driven notification system ensures all applications receive immediate updates when settings change +- Cross-application consistency: settings modified by one app are instantly reflected in all other apps +- No polling required - efficient push-based notification model + +#### Data Persistence +- All settings automatically persist across device reboots +- Leverages the PersistentStore plugin for robust storage +- Default value fallback ensures system always returns valid values + +## Use Cases and Target Scenarios + +### Set-Top Box (STB) Applications +**Scenario**: A cable/satellite STB serving a multi-user household +- Parents configure parental controls to restrict children's viewing during school hours +- Family members set their preferred audio/caption languages based on individual preferences +- Accessibility settings enable elderly users to navigate with voice guidance +- Settings persist across power cycles and software updates + +### Streaming Media Players +**Scenario**: Smart TV or streaming stick used by family members +- Multiple user profiles can be implemented using the UserSettings API +- Consistent caption and audio preferences across all streaming apps +- Centralized privacy settings management for data collection opt-in/opt-out + +### Hospitality and Commercial Deployments +**Scenario**: Hotels, hospitals, or assisted living facilities +- Default settings configured for guests/patients during device provisioning +- Accessibility features easily enabled for users with disabilities +- Uniform presentation language across entire facility deployment + +### Accessibility-Focused Applications +**Scenario**: Applications designed for users with disabilities +- Voice guidance configuration for blind/low-vision users +- High contrast mode for users with visual impairments +- Audio description support for video content +- Adjustable voice speed accommodates different user needs + +### Content Management and Compliance +**Scenario**: Regulatory compliance and content filtering +- Enforce age-appropriate content viewing through parental controls +- Watershed hour compliance for broadcast content +- Audit and reporting capabilities via Inspector interface +- Purchase protection to prevent unauthorized transactions + +## API Capabilities + +### JSON-RPC API +The plugin exposes a comprehensive JSON-RPC API with methods for: +- **Getters**: Retrieve individual settings or bulk settings via Inspector interface +- **Setters**: Update individual settings with validation +- **Events**: Real-time notifications for all setting changes + +### COM-RPC Interfaces +For native service integration: +- `IUserSettings`: Standard user settings interface for get/set operations +- `IUserSettingsInspector`: Bulk query interface for efficient multi-setting retrieval +- `IConfiguration`: Plugin configuration interface + +### Integration Benefits +1. **Zero-Configuration Discovery**: Automatic discovery via Thunder framework +2. **Language-Agnostic**: JSON-RPC API accessible from any programming language +3. **Type-Safe Native Interface**: COM-RPC for C++ services requiring type safety +4. **Versioned API**: Semantic versioning ensures backward compatibility +5. **Security**: Optional security token validation for protected operations + +## Performance and Reliability + +### Performance Characteristics +- **Low Latency**: Settings retrieval typically < 5ms (depends on PersistentStore performance) +- **Minimal Memory Footprint**: Lightweight implementation with no caching overhead +- **Efficient Notifications**: Event-based push model eliminates polling overhead +- **Scalable**: Supports multiple concurrent clients without performance degradation + +### Reliability Features +- **Graceful Degradation**: Returns default values if PersistentStore unavailable +- **Thread-Safe**: Mutex-protected operations ensure data consistency in multi-threaded environments +- **Error Recovery**: Comprehensive error handling with meaningful error codes +- **Validation**: Input parameter validation prevents invalid state persistence +- **Crash Resilience**: Plugin isolation ensures crashes don't affect other Thunder plugins + +### Quality Assurance +- **L1 Unit Tests**: Component-level testing with code coverage tracking +- **L2 Integration Tests**: End-to-end workflow validation +- **Continuous Integration**: Automated testing on every code change +- **Coverity Static Analysis**: Integrated security and quality scanning +- **Compliance**: Follows RDK coding standards and best practices + +## Deployment and Maintenance + +### Easy Deployment +- Standard Thunder plugin packaging +- Configurable via JSON configuration file +- Controlled startup order integration +- Auto-start capability for seamless user experience + +### Maintainability +- Modular architecture separates API layer from implementation +- Comprehensive logging for debugging and diagnostics +- Version tracking via CHANGELOG.md +- Clear separation of concerns enables independent component updates + +### Backward Compatibility +- API versioning strategy maintains compatibility across updates +- Default value mechanism ensures existing clients continue working +- Non-breaking additions via Inspector interface +- Semantic versioning (Current: v2.3.0) + +## Competitive Advantages + +1. **Unified Settings Store**: Single source of truth for all user preferences across the platform +2. **Real-Time Synchronization**: Immediate cross-application consistency without custom integration +3. **Comprehensive Coverage**: Covers audio, video, accessibility, parental controls, and privacy in one plugin +4. **Standards-Based**: Leverages Thunder/WPEFramework industry-standard plugin architecture +5. **Production-Ready**: Battle-tested in commercial RDK deployments worldwide +6. **Active Development**: Regular updates with new features (v2.3.0 released May 2025) +7. **Open Source**: Apache 2.0 license enables customization and community contributions + +## Future Roadmap Considerations + +Potential enhancements based on community feedback: +- Multi-user profile support with per-profile settings +- Cloud synchronization for settings across multiple devices +- Settings import/export functionality +- Enhanced parental control rules engine +- Integration with emerging accessibility standards +- Extended Inspector interface for batch operations +- Settings versioning and rollback capability diff --git a/PackageManager/CMakeLists.txt b/PackageManager/CMakeLists.txt deleted file mode 100644 index 32bce6a..0000000 --- a/PackageManager/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(PackageManager) -set(PLUGIN_NAME ${PROJECT_NAME}RDKEMS) -# When existing/old PackageManager plugin is removed, remove "RDKEMS" from the PLUGIN_NAME -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -message("Setup ${MODULE_NAME}") - -# XXX: ../cmake/FindCurl.cmake is bad -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/;${CMAKE_MODULE_PATH}") -message("CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") - -if (LIB_PACKAGE) - message("LIB_PACKAGE=${LIB_PACKAGE}") - add_compile_options ( -DUSE_LIBPACKAGE ) - include_directories(${SYSROOT_PATH}/${CMAKE_INSTALL_PREFIX}/include/Package) - set(LIB_PACKAGE_LIBRARY "${SYSROOT_PATH}/${CMAKE_INSTALL_PREFIX}/lib/libPackage.so") -endif() - -option(AIMANAGERS_TELEMETRY_METRICS_SUPPORT "AIMANAGERS_TELEMETRY_METRICS_SUPPORT" OFF) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package( Curl REQUIRED) -if (CURL_FOUND) - message("Yay, found curl inc=${CURL_INCLUDE_DIRS} lib=${CURL_LIBRARY}") -endif() - -add_library(${MODULE_NAME} SHARED - PackageManager.cpp - PackageManagerImplementation.cpp - Module.cpp - HttpClient.cpp) - -if(BUILD_REFERENCE) - add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) -endif() - -if(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - message(STATUS "TELEMETRY_METRICS_SUPPORT is enabled") - add_definitions(-DENABLE_AIMANAGERS_TELEMETRY_METRICS) -endif(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - -target_include_directories(${MODULE_NAME} PRIVATE - ../helpers - ${CURL_INCLUDE_DIR} - ${CMAKE_SYSROOT}${CMAKE_INSTALL_PREFIX}/include/${NAMESPACE}/interfaces - ) - -target_link_libraries(${MODULE_NAME} PRIVATE - ${NAMESPACE}Definitions::${NAMESPACE}Definitions - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${CURL_LIBRARY} - ${LIB_PACKAGE_LIBRARY} - ) - -if(RDK_SERVICES_L1_TEST) - find_package( JsonCpp REQUIRED) - if (JSONCPP_FOUND) - message("Yay, found jsoncpp inc=${JSONCPP_INCLUDE_DIRS} lib=${JSONCPP_LIBRARY}") - endif() - target_include_directories(${MODULE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/../entservices-testframework/Tests/mocks) - target_include_directories(${MODULE_NAME} PUBLIC ${JSONCPP_INCLUDE_DIR}) - target_link_libraries(${MODULE_NAME} PUBLIC ${JSONCPP_LIBRARY}) -endif() - -option(ENABLE_UNIT_TESTS "Enable unit tests" OFF) -if(ENABLE_UNIT_TESTS) - target_compile_definitions(${MODULE_NAME} PRIVATE UNIT_TEST) -endif() - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -set(PLUGIN_PACKAGEMANAGER_MODE "Local" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_PACKAGEMANAGER_AUTOSTART "false" CACHE STRING "Deactivated PackageManager plugin") -#write_config() -write_config(INSTALL_NAME ${PLUGIN_NAME}.json) diff --git a/PackageManager/HttpClient.cpp b/PackageManager/HttpClient.cpp deleted file mode 100644 index 63b7dc7..0000000 --- a/PackageManager/HttpClient.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include - -#include "Module.h" - -#include "HttpClient.h" - -HttpClient::HttpClient() { - //curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - if (curl) { - LOGDBG("curl initialized"); - } else { - LOGERR("curl initialize failed"); - } - } - -HttpClient::~HttpClient() { - if (curl) { - curl_easy_cleanup(curl); - } - //curl_global_cleanup(); -} - -HttpClient::Status -HttpClient::downloadFile(const std::string & url, const std::string & fileName, uint32_t rateLimit) { - Status status = Status::Success; - CURLcode cc = CURLE_OK; - FILE *fp; - bCancel = false; - httpCode = 0; - - if (curl) { - (void) curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - setRateLimit(rateLimit); - - fp = fopen(fileName.c_str(), "wb"); - if (fp != NULL) { - (void) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); - (void) curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - - (void) curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - (void) curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this); - (void) curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCb); - - cc = curl_easy_perform(curl); - curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &httpCode); - if (cc == CURLE_OK) { - LOGDBG("Download %s Success", fileName.c_str()); - } else { - LOGERR("Download %s Failed error: %s curl code: %d http code: %ld", fileName.c_str(), curl_easy_strerror(cc), cc, httpCode); - if ( cc == CURLE_WRITE_ERROR ) { - status = Status::DiskError; - } else { - status = Status::HttpError; - } - } - fclose(fp); - } else { - LOGERR("Failed to open %s", fileName.c_str()); - status = Status::DiskError; - } - } - - return status; -} - -size_t HttpClient::progressCb(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow) -{ - HttpClient *pHttpClient = static_cast(ptr); - - int percent = (int)(dlnow * 100 / dltotal); - pHttpClient->progress = percent; - // LOGTRACE("%d completed", percent); - - return pHttpClient->bCancel; -} - -size_t HttpClient::write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) { - // LOGTRACE("size=%ld nmemb=%ld", size, nmemb); - return fwrite(ptr, size, nmemb, stream); -} - diff --git a/PackageManager/HttpClient.h b/PackageManager/HttpClient.h deleted file mode 100644 index d5d4280..0000000 --- a/PackageManager/HttpClient.h +++ /dev/null @@ -1,83 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include - -#include "UtilsLogging.h" - -class HttpClient { - public: - enum Status { - Success, - HttpError, - DiskError - }; - - HttpClient(); - ~HttpClient(); - - Status downloadFile(const std::string & url, const std::string & fileName, uint32_t rateLimit = 0); - - void pause() { curl_easy_pause(curl, CURLPAUSE_RECV | CURLPAUSE_SEND); } - void resume() { curl_easy_pause(curl, CURLPAUSE_CONT); } - void cancel() { bCancel = true; } - void setRateLimit(uint32_t rateLimit) { - LOGDBG("curl rateLimit set to %d", rateLimit); - (void) curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)rateLimit); - } - int getProgress() { return progress; } - - // SSL - void setToken() {} - void setCert() {} - void setCertPath() {} - - // - long getStatusCode() { - return httpCode; - } - - private: - static size_t progressCb(void *ptr, double dltotal, double dlnow, double ultotal, double ulnow); - static size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream); - - private: - CURL *curl; - long httpCode = 0; - bool bCancel = false; - int progress = 0; -}; - -class trace_exit { - public: - trace_exit(std::string fn, uint32_t ln) - : fn(fn) { - std::cout << "--> Entering " << fn << ":" << ln << std::endl; - } - ~trace_exit() { - std::cout << "<-- Exiting " << fn << std::endl; - } - private: - std::string fn; -}; - -#define TR() // trace_exit tr(__FUNCTION__, __LINE__); - diff --git a/PackageManager/Module.cpp b/PackageManager/Module.cpp deleted file mode 100644 index cd6d4d1..0000000 --- a/PackageManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/PackageManager/Module.h b/PackageManager/Module.h deleted file mode 100644 index ddfe87a..0000000 --- a/PackageManager/Module.h +++ /dev/null @@ -1,30 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_PackageManager -#endif - -#include -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/PackageManager/PackageManager.conf.in b/PackageManager/PackageManager.conf.in deleted file mode 100644 index c649e23..0000000 --- a/PackageManager/PackageManager.conf.in +++ /dev/null @@ -1,19 +0,0 @@ -autostart = "@PLUGIN_PACKAGEMANAGER_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.@PLUGIN_NAME@" - -configuration = JSON() - -root = JSON() -root.add("mode", "@PLUGIN_PACKAGEMANAGER_MODE@") -configuration.add("root", root) -configuration.add("downloadDir", "/opt/CDL/") -if boolean("@ADD_DAC_PARAMS@"): - configuration.add("dbpath","@PLUGIN_DAC_DB_PATH@") - configuration.add("appspath","@PLUGIN_DAC_APP_PATH@") - configuration.add("datapath","@PLUGIN_DAC_DATA_PATH@") - configuration.add("annotationsFile","@PLUGIN_DAC_ANTN_FILE@") - configuration.add("annotationsRegex","@PLUGIN_DAC_ANTN_REGEX@") - configuration.add("dacBundleFirmwareCompatibilityKey", "@PLUGIN_DAC_BUN_FIRM_COMP_KEY@") - configuration.add("dacBundlePlatformNameOverride", "@PLUGIN_DAC_BUN_PLATNAME_OVERRIDE@") - configuration.add("configUrl", "@PLUGIN_DAC_CONFIGURL@") diff --git a/PackageManager/PackageManager.cpp b/PackageManager/PackageManager.cpp deleted file mode 100644 index f21d8de..0000000 --- a/PackageManager/PackageManager.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "PackageManager.h" -#include - -namespace WPEFramework { - -namespace Plugin -{ - - namespace { - static Metadata metadata( - // Version - 1, 0, 0, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - PackageManager::PackageManager() - : mConnectionId(0) - , mService(nullptr) - , mPackageDownloader(nullptr) - , mPackageInstaller(nullptr) - , mPackageHandler(nullptr) - , mNotificationSink(*this) - { - } - - const string PackageManager::Initialize(PluginHost::IShell * service) - { - string message; - - ASSERT(service != nullptr); - ASSERT(mService == nullptr); - ASSERT(mConnectionId == 0); - ASSERT(mPackageDownloader == nullptr); - ASSERT(mPackageInstaller == nullptr); - ASSERT(mPackageHandler == nullptr); - mService = service; - mService->AddRef(); - - LOGINFO(); - // Register the Process::Notification stuff. The Remote process might die before we get a - // change to "register" the sink for these events !!! So do it ahead of instantiation. - mService->Register(&mNotificationSink); - - mPackageDownloader = service->Root(mConnectionId, RPC::CommunicationTimeOut, _T("PackageManagerImplementation")); - if (mPackageDownloader != nullptr) { - mPackageDownloader->Initialize(service); - - mPackageDownloader->Register(&mNotificationSink); - Exchange::JPackageDownloader::Register(*this, mPackageDownloader); - - mPackageInstaller = mPackageDownloader->QueryInterface(); - if (mPackageInstaller != nullptr) { - mPackageInstaller->Register(&mNotificationSink); - Exchange::JPackageInstaller::Register(*this, mPackageInstaller); - } else { - LOGERR("Failed to get instance of IPackageInstaller"); - } - - mPackageHandler = mPackageDownloader->QueryInterface(); - if (mPackageHandler != nullptr) { - Exchange::JPackageHandler::Register(*this, mPackageHandler); - } else { - LOGERR("Failed to get instance of IPackageHandler"); - } - } - else { - message = _T("PackageManager could not be instantiated."); - } - - // On success return empty, to indicate there is no error text. - return (message); - } - - void PackageManager::Deinitialize(PluginHost::IShell* service VARIABLE_IS_NOT_USED) - { - LOGINFO(); - if (mService != nullptr) { - ASSERT(mService == service); - mService->Unregister(&mNotificationSink); - - if (mPackageHandler != nullptr) { - Exchange::JPackageHandler::Unregister(*this); - } - - if (mPackageInstaller != nullptr) { - mPackageInstaller->Unregister(&mNotificationSink); - Exchange::JPackageInstaller::Unregister(*this); - } - - if (mPackageDownloader != nullptr) { - mPackageDownloader->Unregister(&mNotificationSink); - Exchange::JPackageDownloader::Unregister(*this); - - RPC::IRemoteConnection* connection(mService->RemoteConnection(mConnectionId)); - if (mPackageDownloader->Release() != Core::ERROR_DESTRUCTION_SUCCEEDED) { - LOGERR("PackageManager Plugin is not properly destructed. %d", mConnectionId); - } - mPackageDownloader = nullptr; - - // The connection can disappear in the meantime... - if (connection != nullptr) { - // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill :-) - connection->Terminate(); - connection->Release(); - } - } - - mService->Release(); - mService = nullptr; - mConnectionId = 0; - SYSLOG(Logging::Shutdown, (string(_T("PackageManager de-initialised")))); - } - } - - string PackageManager::Information() const - { - // No additional info to report. - return (string()); - } - - - void PackageManager::Deactivated(RPC::IRemoteConnection* connection) - { - // This can potentially be called on a socket thread, so the deactivation (wich in turn kills this object) must be done - // on a seperate thread. Also make sure this call-stack can be unwound before we are totally destructed. - if (mConnectionId == connection->Id()) { - ASSERT(mService != nullptr); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - void PackageManager::NotificationHandler::OnAppDownloadStatus(Exchange::IPackageDownloader::IPackageInfoIterator* const packageInfos) - { - JsonArray packageInfoArray; - if (packageInfos != nullptr) - { - Exchange::IPackageDownloader::PackageInfo resultItem{}; - - while (packageInfos->Next(resultItem) == true) - { - JsonObject packageInfoJson; - packageInfoJson["downloadId"] = resultItem.downloadId; - packageInfoJson["fileLocator"] = resultItem.fileLocator; - packageInfoJson["failReason"] = (resultItem.reason == Exchange::IPackageDownloader::Reason::NONE) ? "NONE" : - (resultItem.reason == Exchange::IPackageDownloader::Reason::DOWNLOAD_FAILURE) ? "DOWNLOAD_FAILURE" : - (resultItem.reason == Exchange::IPackageDownloader::Reason::DISK_PERSISTENCE_FAILURE) ? "DISK_PERSISTENCE_FAILURE" : "UNKNOWN"; - packageInfoArray.Add(packageInfoJson); - } - - Core::JSON::Container eventPayload; - eventPayload.Add(_T("jsonresponse"), &packageInfoArray); - //unable to remove escaped characters from fileLocator as ToString called in Notify() always adds escape characters. - - mParent.Notify(_T("onAppDownloadStatus"), eventPayload); - } - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/PackageManager/PackageManager.h b/PackageManager/PackageManager.h deleted file mode 100644 index 4b631b5..0000000 --- a/PackageManager/PackageManager.h +++ /dev/null @@ -1,124 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" - -#include -#include -#include -#include -#include - -#include "UtilsLogging.h" - -namespace WPEFramework { -namespace Plugin { - - class PackageManager : public PluginHost::IPlugin, - public PluginHost::JSONRPC { - private: - class NotificationHandler - : public RPC::IRemoteConnection::INotification - , public Exchange::IPackageDownloader::INotification - , public Exchange::IPackageInstaller::INotification - { - public: - NotificationHandler() = delete; - NotificationHandler(const NotificationHandler&) = delete; - NotificationHandler(NotificationHandler&&) = delete; - NotificationHandler& operator=(const NotificationHandler&) = delete; - NotificationHandler& operator=(NotificationHandler&&) = delete; - - NotificationHandler(PackageManager& parent) - : mParent(parent) - { - } - ~NotificationHandler() override = default; - - public: - void Activated(RPC::IRemoteConnection* /* connection */) override - { - } - void Deactivated(RPC::IRemoteConnection* connection) override - { - mParent.Deactivated(connection); - } - void Terminated (RPC::IRemoteConnection* /* connection */) override - { - } - - void OnAppDownloadStatus(Exchange::IPackageDownloader::IPackageInfoIterator* const packageInfos) override; - void OnAppInstallationStatus(const string& jsonresponse) override - { - LOGTRACE(); - Exchange::JPackageInstaller::Event::OnAppInstallationStatus(mParent, jsonresponse); - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - INTERFACE_ENTRY(Exchange::IPackageDownloader::INotification) - END_INTERFACE_MAP - - private: - PackageManager& mParent; - }; - public: - PackageManager(const PackageManager&) = delete; - PackageManager(PackageManager&&) = delete; - PackageManager& operator=(const PackageManager&) = delete; - PackageManager& operator=(PackageManager&) = delete; - - PackageManager(); - ~PackageManager() override = default; - - // Build QueryInterface implementation, specifying all possible interfaces to be returned. - BEGIN_INTERFACE_MAP(PackageManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IPackageDownloader, mPackageDownloader) - INTERFACE_AGGREGATE(Exchange::IPackageInstaller, mPackageInstaller) - INTERFACE_AGGREGATE(Exchange::IPackageHandler, mPackageHandler) - END_INTERFACE_MAP - - public: - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - uint32_t mConnectionId; - PluginHost::IShell* mService; - Exchange::IPackageDownloader* mPackageDownloader; - Exchange::IPackageInstaller* mPackageInstaller; - Exchange::IPackageHandler* mPackageHandler; - - Core::Sink mNotificationSink; - - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PackageManager/PackageManagerImplementation.cpp b/PackageManager/PackageManagerImplementation.cpp deleted file mode 100644 index ff229b5..0000000 --- a/PackageManager/PackageManagerImplementation.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include // Required for PRIu64 - -#include "PackageManagerImplementation.h" - -/* Until we don't get it from Package configuration, use size as 1MB */ -#define STORAGE_MAX_SIZE 1024 - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(PackageManagerImplementation, 1, 0); - - #define CHECK_CACHE() { if ((packageImpl.get() == nullptr) || (!cacheInitialized)) { \ - LOGERR("Cache is not initialized!"); \ - return Core::ERROR_UNAVAILABLE; \ - }} - - PackageManagerImplementation::PackageManagerImplementation() - : mDownloaderNotifications() - , mInstallNotifications() - , mNextDownloadId(1000) - , mCurrentservice(nullptr) - , mStorageManagerObject(nullptr) -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - , mTelemetryMetricsObject(nullptr) -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - { - LOGINFO("ctor PackageManagerImplementation: %p", this); - mHttpClient = std::unique_ptr(new HttpClient); - } - - PackageManagerImplementation::~PackageManagerImplementation() - { - LOGINFO("dtor PackageManagerImplementation: %p", this); - - std::list::iterator index(mInstallNotifications.begin()); - { - while (index != mInstallNotifications.end()) { - (*index)->Release(); - index++; - } - } - mInstallNotifications.clear(); - - releaseStorageManagerObject(); - - std::list::iterator itDownloader(mDownloaderNotifications.begin()); - { - while (itDownloader != mDownloaderNotifications.end()) { - (*itDownloader)->Release(); - itDownloader++; - } - } - mDownloaderNotifications.clear(); - } - - Core::hresult PackageManagerImplementation::Register(Exchange::IPackageDownloader::INotification* notification) - { - LOGINFO(); - ASSERT(notification != nullptr); - - mAdminLock.Lock(); - ASSERT(std::find(mDownloaderNotifications.begin(), mDownloaderNotifications.end(), notification) == mDownloaderNotifications.end()); - if (std::find(mDownloaderNotifications.begin(), mDownloaderNotifications.end(), notification) == mDownloaderNotifications.end()) { - mDownloaderNotifications.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult PackageManagerImplementation::Unregister(Exchange::IPackageDownloader::INotification* notification) - { - LOGINFO(); - ASSERT(notification != nullptr); - Core::hresult result = Core::ERROR_NONE; - - mAdminLock.Lock(); - auto item = std::find(mDownloaderNotifications.begin(), mDownloaderNotifications.end(), notification); - if (item != mDownloaderNotifications.end()) { - notification->Release(); - mDownloaderNotifications.erase(item); - } else { - result = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult PackageManagerImplementation::Initialize(PluginHost::IShell* service) - { - Core::hresult result = Core::ERROR_GENERAL; - LOGINFO("entry"); - - if (service != nullptr) { - mCurrentservice = service; - mCurrentservice->AddRef(); - if (Core::ERROR_NONE != createStorageManagerObject()) { - LOGERR("Failed to create createStorageManagerObject"); - } else { - LOGINFO("created createStorageManagerObject"); - result = Core::ERROR_NONE; - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (nullptr == (mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"))) - { - LOGERR("mTelemetryMetricsObject is null \n"); - } - else - { - LOGINFO("created TelemetryMetrics Object"); - } -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - configStr = service->ConfigLine().c_str(); - LOGINFO("ConfigLine=%s", service->ConfigLine().c_str()); - PackageManagerImplementation::Configuration config; - config.FromString(service->ConfigLine()); - downloadDir = config.downloadDir; - LOGINFO("downloadDir=%s", downloadDir.c_str()); - - //std::filesystem::create_directories(path); // XXX: need C++17 - int rc = mkdir(downloadDir.c_str(), 0777); - if (rc) { - if (errno != EEXIST) { - LOGERR("Failed to create dir '%s' rc: %d errno=%d", downloadDir.c_str(), rc, errno); - } - } else { - LOGDBG("created dir '%s'", downloadDir.c_str()); - } - - mDownloadThreadPtr = std::unique_ptr(new std::thread(&PackageManagerImplementation::downloader, this, 1)); - } else { - LOGERR("service is null \n"); - } - - LOGINFO("exit"); - return result; - } - - Core::hresult PackageManagerImplementation::Deinitialize(PluginHost::IShell* service) - { - Core::hresult result = Core::ERROR_NONE; - LOGINFO(); - - done = true; - cv.notify_one(); - mDownloadThreadPtr->join(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (nullptr != mTelemetryMetricsObject) - { - LOGINFO("TelemetryMetrics object released\n"); - mTelemetryMetricsObject->Release(); - mTelemetryMetricsObject = nullptr; - } -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - const std::string markerFile = PACKAGE_MANAGER_MARKER_FILE; - if (std::remove(markerFile.c_str()) == 0) { - LOGINFO("Deleted marker file: %s", markerFile.c_str()); - } else { - LOGERR("Failed to delete marker file: %s (errno=%d)", markerFile.c_str(), errno); - } - - mCurrentservice->Release(); - mCurrentservice = nullptr; - - return result; - } - - Core::hresult PackageManagerImplementation::createStorageManagerObject() - { - Core::hresult status = Core::ERROR_GENERAL; - - if (nullptr == mCurrentservice) { - LOGERR("mCurrentservice is null \n"); - } else if (nullptr == (mStorageManagerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.StorageManager"))) { - LOGERR("mStorageManagerObject is null \n"); - } else { - LOGINFO("created StorageManager Object\n"); - status = Core::ERROR_NONE; - } - return status; - } - - void PackageManagerImplementation::releaseStorageManagerObject() - { - ASSERT(nullptr != mStorageManagerObject); - if(mStorageManagerObject) { - mStorageManagerObject->Release(); - mStorageManagerObject = nullptr; - } - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - time_t PackageManagerImplementation::getCurrentTimestamp() - { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((time_t)ts.tv_sec * 1000) + ((time_t)ts.tv_nsec / 1000000)); - } - - void PackageManagerImplementation::recordAndPublishTelemetryData(const std::string& marker, const std::string& appId, - time_t requestTime, PackageManagerImplementation::PackageFailureErrorCode errorCode) - { - std::string telemetryMetrics = ""; - JsonObject jsonParam; - int duration = 0; - bool shouldProcessMarker = true; - bool publish = true; - - if (marker.empty()) { - LOGERR("Telemetry marker is empty"); - } - else { - if (mTelemetryMetricsObject == nullptr) { - LOGINFO("mTelemetryMetricsObject is null, recreate it"); - mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"); - - if (mTelemetryMetricsObject == nullptr) { - LOGERR("mTelemetryMetricsObject is still null"); - } - } - - if (mTelemetryMetricsObject != nullptr) { - time_t currentTime = getCurrentTimestamp(); - duration = static_cast(currentTime - requestTime); - LOGINFO("End time for %s: %lu", marker.c_str(), currentTime); - - if (marker == TELEMETRY_MARKER_LAUNCH_TIME) { - jsonParam["packageManagerLockTime"] = duration; - publish = false; - } - else if (marker == TELEMETRY_MARKER_CLOSE_TIME) { - jsonParam["packageManagerUnlockTime"] = duration; - publish = false; - } - else if (marker == TELEMETRY_MARKER_INSTALL_TIME) { - jsonParam["installTime"] = duration; - } - else if (marker == TELEMETRY_MARKER_UNINSTALL_TIME) { - jsonParam["uninstallTime"] = duration; - } - else if (marker == TELEMETRY_MARKER_INSTALL_ERROR || marker == TELEMETRY_MARKER_UNINSTALL_ERROR) { - jsonParam["errorCode"] = static_cast(errorCode); - } - else { - LOGERR("Unknown telemetry marker: %s", marker.c_str()); - shouldProcessMarker = false; - } - - if (true == shouldProcessMarker) { - jsonParam["appId"] = appId; - - if (jsonParam.ToString(telemetryMetrics)) { - LOGINFO("Record appId %s marker %s duration %d", appId.c_str(), marker.c_str(), duration); - - if (mTelemetryMetricsObject->Record(appId, telemetryMetrics, marker) != Core::ERROR_NONE) { - LOGERR("Telemetry Record Failed"); - } - - if (publish) { - LOGINFO("Publish appId %s marker %s", appId.c_str(), marker.c_str()); - - if (mTelemetryMetricsObject->Publish(appId, marker) != Core::ERROR_NONE) { - LOGERR("Telemetry Publish Failed"); - } - } - } else { - LOGERR("Failed to serialize telemetry metrics"); - } - } - } - } - - return; - } -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - // IPackageDownloader methods - Core::hresult PackageManagerImplementation::Download(const string& url, - const Exchange::IPackageDownloader::Options &options, - Exchange::IPackageDownloader::DownloadId &downloadId) - { - Core::hresult result = Core::ERROR_NONE; - - if (!mCurrentservice->SubSystems()->IsActive(PluginHost::ISubSystem::INTERNET)) { - return Core::ERROR_UNAVAILABLE; - } - - std::lock_guard lock(mMutex); - - DownloadInfoPtr di = DownloadInfoPtr(new DownloadInfo(url, std::to_string(++mNextDownloadId), options.retries, options.rateLimit)); - std::string filename = downloadDir + "package" + di->GetId(); - di->SetFileLocator(filename); - if (options.priority) { - mDownloadQueue.push_front(di); - } else { - mDownloadQueue.push_back(di); - } - cv.notify_one(); - - downloadId.downloadId = di->GetId(); - - return result; - } - - Core::hresult PackageManagerImplementation::Pause(const string &downloadId) - { - Core::hresult result = Core::ERROR_NONE; - - LOGDBG("Pausing '%s'", downloadId.c_str()); - if (mInprogressDownload.get() != nullptr) { - if (downloadId.compare(mInprogressDownload->GetId()) == 0) { - mHttpClient->pause(); - LOGDBG("%s paused", downloadId.c_str()); - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - LOGERR("Pause Failed, mInprogressDownload=%p", mInprogressDownload.get()); - result = Core::ERROR_GENERAL; - } - - return result; - } - - Core::hresult PackageManagerImplementation::Resume(const string &downloadId) - { - Core::hresult result = Core::ERROR_NONE; - - LOGDBG("Resuming '%s'", downloadId.c_str()); - if (mInprogressDownload.get() != nullptr) { - if (downloadId.compare(mInprogressDownload->GetId()) == 0) { - mHttpClient->resume(); - LOGDBG("%s resumed", downloadId.c_str()); - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - LOGERR("Resume Failed, mInprogressDownload=%p", mInprogressDownload.get()); - result = Core::ERROR_GENERAL; - } - - return result; - } - - Core::hresult PackageManagerImplementation::Cancel(const string &downloadId) - { - Core::hresult result = Core::ERROR_NONE; - - LOGDBG("Cancelling '%s'", downloadId.c_str()); - if (mInprogressDownload.get() != nullptr) { - if (downloadId.compare(mInprogressDownload->GetId()) == 0) { - mInprogressDownload->Cancel(); - mHttpClient->cancel(); - LOGDBG("%s cancelled", downloadId.c_str()); - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - LOGERR("Cancel Failed, mInprogressDownload=%p", mInprogressDownload.get()); - result = Core::ERROR_GENERAL; - } - - return result; - } - - Core::hresult PackageManagerImplementation::Delete(const string &fileLocator) - { - Core::hresult result = Core::ERROR_NONE; - - if ((mInprogressDownload.get() != nullptr) && (fileLocator.compare(mInprogressDownload->GetFileLocator()) == 0)) { - LOGWARN("%s in in progress", fileLocator.c_str()); - result = Core::ERROR_GENERAL; - } else { - if (remove(fileLocator.c_str()) == 0) { - LOGDBG("Deleted %s", fileLocator.c_str()); - } else { - LOGERR("'%s' delete failed", fileLocator.c_str()); - result = Core::ERROR_GENERAL; - } - } - - return result; - } - - Core::hresult PackageManagerImplementation::Progress(const string &downloadId, ProgressInfo &progress) - { - Core::hresult result = Core::ERROR_NONE; - LOGDBG("'%s'", downloadId.c_str()); - if (mInprogressDownload.get() != nullptr) { - progress.progress = mHttpClient->getProgress(); - } else { - result = Core::ERROR_GENERAL; - } - - return result; - } - - Core::hresult PackageManagerImplementation::GetStorageInformation(uint32_t "aKB, uint32_t &usedKB) - { - Core::hresult result = Core::ERROR_NONE; - LOGDBG(); - return result; - } - - Core::hresult PackageManagerImplementation::RateLimit(const string &downloadId, const uint64_t &limit) - { - Core::hresult result = Core::ERROR_NONE; - LOGDBG("'%s' limit=%" PRIu64, downloadId.c_str(), limit); - if (mInprogressDownload.get() != nullptr) { - if (downloadId.compare(mInprogressDownload->GetId()) == 0) { - mHttpClient->setRateLimit(limit); - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - LOGERR("set RateLimit Failed, mInprogressDownload=%p", mInprogressDownload.get()); - result = Core::ERROR_GENERAL; - } - return result; - } - - - // IPackageInstaller methods - Core::hresult PackageManagerImplementation::Install(const string &packageId, const string &version, - IPackageInstaller::IKeyValueIterator* const& additionalMetadata, - const string &fileLocator, Exchange::IPackageInstaller::FailReason &failReason) - { - Core::hresult result = Core::ERROR_GENERAL; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - PackageManagerImplementation::PackageFailureErrorCode packageFailureErrorCode = PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE; - /* Get current timestamp at the start of Install for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - CHECK_CACHE() - if (fileLocator.empty()) { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordAndPublishTelemetryData(TELEMETRY_MARKER_INSTALL_ERROR, packageId, requestTime, PackageManagerImplementation::PackageFailureErrorCode::ERROR_SIGNATURE_VERIFICATION_FAILURE); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - LOGERR("fileLocator is empty '%s' ver:'%s'", packageId.c_str(), version.c_str()); - return Core::ERROR_INVALID_SIGNATURE; - } - LOGDBG("Installing '%s' ver:'%s' fileLocator: '%s'", packageId.c_str(), version.c_str(), fileLocator.c_str()); - - packagemanager::NameValues keyValues; - if (additionalMetadata != nullptr) { - struct IPackageInstaller::KeyValue kv; - while (additionalMetadata->Next(kv) == true) { - LOGDBG("name: %s val: %s", kv.name.c_str(), kv.value.c_str()); - keyValues.push_back(std::make_pair(kv.name, kv.value)); - } - } - - std::lock_guard lock(mtxState); - bool bNewEntry = false; - StateKey key { packageId, version }; - auto it = mState.find( key ); - State tempState; - bool found = it != mState.end(); - State &state = found ? it->second : tempState; - state.installState = InstallState::INSTALLING; - - NotifyInstallStatus(packageId, version, state); - string installedVersion = GetInstalledVersion(packageId); - if (installedVersion.empty()) { - // No other versions - bNewEntry = true; - } else { - if (installedVersion.compare(version) == 0) { - // Same version already installed, upgrading - } else { - // different version - StateKey installedKey { packageId, installedVersion }; - auto it = mState.find( installedKey ); - bNewEntry = true; - if (it != mState.end()) { - State &installedState = it->second; - if ( installedState.mLockCount ) { - LOGWARN("App is locked id: '%s' ver: '%s' count:%d", packageId.c_str(), installedVersion.c_str(), installedState.mLockCount); - state.installState = InstallState::INSTALLATION_BLOCKED; - state.blockedInstallData.version = version; - state.blockedInstallData.keyValues = keyValues; - state.blockedInstallData.fileLocator = fileLocator; - NotifyInstallStatus(packageId, version, state); - } - } - } - } - - if (state.installState == InstallState::INSTALLING) { - result = Install(packageId, version, keyValues, fileLocator, state); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (result != Core::ERROR_NONE) { - packageFailureErrorCode = (state.failReason == FailReason::PACKAGE_MISMATCH_FAILURE) - ? PackageManagerImplementation::PackageFailureErrorCode::ERROR_PACKAGE_MISMATCH_FAILURE - : PackageManagerImplementation::PackageFailureErrorCode::ERROR_SIGNATURE_VERIFICATION_FAILURE; - - } - recordAndPublishTelemetryData(((PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE == packageFailureErrorCode) ? TELEMETRY_MARKER_INSTALL_TIME : TELEMETRY_MARKER_INSTALL_ERROR), - packageId, - requestTime, - packageFailureErrorCode); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - } - - if (bNewEntry) { - LOGDBG("Inserting id: %s ver: %s ", key.first.c_str(), key.second.c_str()); - mState.insert( { key, state } ); - } - - return result; - } - - Core::hresult PackageManagerImplementation::Uninstall(const string &packageId, string &errorReason ) - { - Core::hresult result = Core::ERROR_GENERAL; - string version = GetInstalledVersion(packageId); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - PackageManagerImplementation::PackageFailureErrorCode packageFailureErrorCode = PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE; - /* Get current timestamp at the start of Uninstall for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - LOGDBG("Uninstalling id: '%s' ver: '%s'", packageId.c_str(), version.c_str()); - CHECK_CACHE() - - std::lock_guard lock(mtxState); - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - if (state.mLockCount == 0) { - if (nullptr == mStorageManagerObject) { - LOGINFO("Create StorageManager object"); - if (Core::ERROR_NONE != createStorageManagerObject()) { - LOGERR("Failed to create StorageManager"); - } - } - ASSERT (nullptr != mStorageManagerObject); - if (nullptr != mStorageManagerObject) { - if(mStorageManagerObject->DeleteStorage(packageId, errorReason) == Core::ERROR_NONE) { - LOGINFO("DeleteStorage done"); - #if defined(USE_LIBPACKAGE) || defined(UNIT_TEST) - // XXX: what if DeleteStorage() fails, who Uninstall the package - packagemanager::Result pmResult = packageImpl->Uninstall(packageId); - if (pmResult == packagemanager::SUCCESS) { - result = Core::ERROR_NONE; - } else { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - packageFailureErrorCode = (pmResult == packagemanager::Result::VERSION_MISMATCH) ? - PackageManagerImplementation::PackageFailureErrorCode::ERROR_PACKAGE_MISMATCH_FAILURE : PackageManagerImplementation::PackageFailureErrorCode::ERROR_SIGNATURE_VERIFICATION_FAILURE; -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - } - #endif - state.installState = InstallState::UNINSTALLED; - NotifyInstallStatus(packageId, version, state); - } else { - LOGERR("DeleteStorage failed with result :%d errorReason [%s]", result, errorReason.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - packageFailureErrorCode = PackageManagerImplementation::PackageFailureErrorCode::ERROR_PERSISTENCE_FAILURE; -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - } - } - } else { - state.installState = InstallState::UNINSTALLING; - NotifyInstallStatus(packageId, version, state); - - LOGWARN("App is locked, uninstall delayed id: '%s' ver: '%s' count:%d", packageId.c_str(), version.c_str(), state.mLockCount); - state.installState = InstallState::UNINSTALL_BLOCKED; - NotifyInstallStatus(packageId, version, state); - } // mLockCount == 0 - } else { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - packageFailureErrorCode = PackageManagerImplementation::PackageFailureErrorCode::ERROR_VERSION_NOT_FOUND; -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordAndPublishTelemetryData(((PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE == packageFailureErrorCode) ? TELEMETRY_MARKER_UNINSTALL_TIME : TELEMETRY_MARKER_UNINSTALL_ERROR), - packageId, - requestTime, - packageFailureErrorCode); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - return result; - } - - Core::hresult PackageManagerImplementation::ListPackages(Exchange::IPackageInstaller::IPackageIterator*& packages) - { - CHECK_CACHE() - LOGTRACE("entry"); - Core::hresult result = Core::ERROR_NONE; - std::list packageList; - std::lock_guard lock(mtxState); - - for (auto const& [key, state] : mState) { - Exchange::IPackageInstaller::Package package; - package.packageId = key.first.c_str(); - package.version = key.second.c_str(); - package.state = state.installState; - package.sizeKb = state.runtimeConfig.dataImageSize; - packageList.emplace_back(package); - } - - packages = (Core::Service>::Create(packageList)); - - LOGTRACE("exit"); - - return result; - } - - Core::hresult PackageManagerImplementation::Config(const string &packageId, const string &version, Exchange::RuntimeConfig& runtimeConfig) - { - CHECK_CACHE() - LOGDBG("id: '%s' ver: '%s'", packageId.c_str(), version.c_str()); - Core::hresult result = Core::ERROR_GENERAL; - std::lock_guard lock(mtxState); - - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - if (state.installState == InstallState::INSTALLED) { - getRuntimeConfig(state.runtimeConfig, runtimeConfig); - result = Core::ERROR_NONE; - } - } - if (result == Core::ERROR_GENERAL) { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); - - } - - return result; - } - - Core::hresult PackageManagerImplementation::PackageState(const string &packageId, const string &version, - Exchange::IPackageInstaller::InstallState &installState) - { - CHECK_CACHE() - LOGDBG("id: '%s' ver: '%s'", packageId.c_str(), version.c_str()); - Core::hresult result = Core::ERROR_NONE; - std::lock_guard lock(mtxState); - - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - installState = state.installState; - LOGDBG("id: '%s' ver: '%s' state: %s", packageId.c_str(), version.c_str(), getInstallState(installState).c_str()); - } else { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); - result = Core::ERROR_GENERAL; - } - - return result; - } - - Core::hresult PackageManagerImplementation::Register(Exchange::IPackageInstaller::INotification *notification) - { - Core::hresult result = Core::ERROR_NONE; - - LOGINFO(); - ASSERT(notification != nullptr); - mAdminLock.Lock(); - ASSERT(std::find(mInstallNotifications.begin(), mInstallNotifications.end(), notification) == mInstallNotifications.end()); - if (std::find(mInstallNotifications.begin(), mInstallNotifications.end(), notification) == mInstallNotifications.end()) { - mInstallNotifications.push_back(notification); - notification->AddRef(); - } - mAdminLock.Unlock(); - - return result; - } - - Core::hresult PackageManagerImplementation::Unregister(Exchange::IPackageInstaller::INotification *notification) { - Core::hresult result = Core::ERROR_NONE; - - LOGINFO(); - mAdminLock.Lock(); - auto item = std::find(mInstallNotifications.begin(), mInstallNotifications.end(), notification); - if (item != mInstallNotifications.end()) { - notification->Release(); - mInstallNotifications.erase(item); - } - else { - result = Core::ERROR_GENERAL; - } - mAdminLock.Unlock(); - - return result; - } - - // IPackageHandler methods - Core::hresult PackageManagerImplementation::Lock(const string &packageId, const string &version, - const Exchange::IPackageHandler::LockReason &lockReason, - uint32_t &lockId, string &unpackedPath, Exchange::RuntimeConfig& runtimeConfig, - Exchange::IPackageHandler::ILockIterator*& appMetadata - ) - { - Core::hresult result = Core::ERROR_NONE; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of Lock for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - LOGDBG("id: %s ver: %s reason=%u", packageId.c_str(), version.c_str(), (uint8_t) lockReason); - CHECK_CACHE() - - std::lock_guard lock(mtxState); - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - #if defined(USE_LIBPACKAGE) || defined(UNIT_TEST) - string gatewayMetadataPath; - bool locked = (state.mLockCount > 0); - LOGDBG("id: %s ver: %s locked: %d", packageId.c_str(), version.c_str(), locked); - if (locked) { - lockId = ++state.mLockCount; - } else { - packagemanager::ConfigMetaData config; - packagemanager::NameValues locks; - packagemanager::Result pmResult = packageImpl->Lock(packageId, version, state.unpackedPath, config, locks); - LOGDBG("unpackedPath=%s", unpackedPath.c_str()); - // save the new config in state - getRuntimeConfig(config, state.runtimeConfig); // XXX: config is unnecessary in Lock ?! - if (pmResult == packagemanager::SUCCESS) { - lockId = ++state.mLockCount; - - state.additionalLocks.clear(); - for (packagemanager::NameValue nv : locks) { - Exchange::IPackageHandler::AdditionalLock lock; - lock.packageId = nv.first; - lock.version = nv.second; - state.additionalLocks.emplace_back(lock); - } - LOGDBG("Locked. id: %s ver: %s additionalLocks=%zu", packageId.c_str(), version.c_str(), state.additionalLocks.size()); - } else { - LOGERR("Lock Failed id: %s ver: %s", packageId.c_str(), version.c_str()); - result = Core::ERROR_GENERAL; - } - } - - if (result == Core::ERROR_NONE) { - getRuntimeConfig(state.runtimeConfig, runtimeConfig); - unpackedPath = state.unpackedPath; - appMetadata = Core::Service>::Create(state.additionalLocks); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordAndPublishTelemetryData(TELEMETRY_MARKER_LAUNCH_TIME, - packageId, - requestTime, - PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - } - #endif - - LOGDBG("id: %s ver: %s lock count:%d", packageId.c_str(), version.c_str(), state.mLockCount); - } else { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); - result = Core::ERROR_BAD_REQUEST; - } - - return result; - } - - // XXX: right way to do this is via copy ctor, when we move to Thunder 5.2 and have common struct RuntimeConfig - void PackageManagerImplementation::getRuntimeConfig(const Exchange::RuntimeConfig &config, Exchange::RuntimeConfig &runtimeConfig) - { - runtimeConfig.dial = config.dial; - runtimeConfig.wanLanAccess = config.wanLanAccess; - runtimeConfig.thunder = config.thunder; - runtimeConfig.systemMemoryLimit = config.systemMemoryLimit; - runtimeConfig.gpuMemoryLimit = config.gpuMemoryLimit; - runtimeConfig.envVariables = config.envVariables; - - runtimeConfig.userId = config.userId; - runtimeConfig.groupId = config.groupId; - runtimeConfig.dataImageSize = config.dataImageSize; - - runtimeConfig.fkpsFiles = config.fkpsFiles; - runtimeConfig.appType = config.appType; - runtimeConfig.appPath = config.appPath; - runtimeConfig.command = config.command; - runtimeConfig.runtimePath = config.runtimePath; - } - - void PackageManagerImplementation::getRuntimeConfig(const packagemanager::ConfigMetaData &config, Exchange::RuntimeConfig &runtimeConfig) - { - runtimeConfig.dial = config.dial; - runtimeConfig.wanLanAccess = config.wanLanAccess; - runtimeConfig.thunder = config.thunder; - runtimeConfig.systemMemoryLimit = config.systemMemoryLimit; - runtimeConfig.gpuMemoryLimit = config.gpuMemoryLimit; - - JsonArray vars = JsonArray(); - for (auto str: config.envVars) { - vars.Add(str); - } - vars.ToString(runtimeConfig.envVariables); - - runtimeConfig.userId = config.userId; - runtimeConfig.groupId = config.groupId; - runtimeConfig.dataImageSize = config.dataImageSize; - - JsonArray list = JsonArray(); - for (const std::string &fkpsFile : config.fkpsFiles) { - list.Add(fkpsFile); - } - - if (!list.ToString(runtimeConfig.fkpsFiles)) { - LOGERR("Failed to stringify fkpsFiles to JsonArray"); - } - runtimeConfig.appType = config.appType == packagemanager::ApplicationType::SYSTEM ? "SYSTEM" : "INTERACTIVE"; - runtimeConfig.appPath = config.appPath; - runtimeConfig.command = config.command; - runtimeConfig.runtimePath = config.runtimePath; - } - - Core::hresult PackageManagerImplementation::Unlock(const string &packageId, const string &version) - { - Core::hresult result = Core::ERROR_NONE; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of Lock for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - LOGDBG("id: %s ver: %s", packageId.c_str(), version.c_str()); - CHECK_CACHE() - - std::lock_guard lock(mtxState); - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - #if defined(USE_LIBPACKAGE) || defined(UNIT_TEST) - if (state.mLockCount) { - LOGDBG("id: %s ver: %s lock count:%d state:%d", packageId.c_str(), version.c_str(), - state.mLockCount, (int) state.installState); - if (--state.mLockCount == 0) { - string blockedVer = GetBlockedVersion(packageId); - LOGDBG("blockedVer: %s", blockedVer.c_str()); - auto itBlocked = mState.find( { packageId, blockedVer } ); - if (itBlocked != mState.end()) { - auto &stateBlocked = itBlocked->second; - LOGDBG("blockedVer: '%s' state: %d", blockedVer.c_str(), (unsigned) stateBlocked.installState); - stateBlocked.unpackedPath = ""; - if (stateBlocked.installState == InstallState::INSTALLATION_BLOCKED) { - auto blockedData = stateBlocked.blockedInstallData; - if (Install(packageId, blockedData.version, blockedData.keyValues, blockedData.fileLocator, stateBlocked) == Core::ERROR_NONE) { - LOGDBG("Blocked package installed. id: %s ver: %s", packageId.c_str(), blockedVer.c_str()); - state.installState = InstallState::UNINSTALLED; - } else { - LOGERR("Blocked package installtion failed id: %s ver: %s", packageId.c_str(), blockedVer.c_str()); - } - } else if (stateBlocked.installState == InstallState::UNINSTALL_BLOCKED) { - string errorReason; - if (Uninstall(packageId, errorReason) == Core::ERROR_NONE) { - LOGDBG("Blocked package uninstalled id: %s ver: %s", packageId.c_str(), blockedVer.c_str()); - } else { - LOGERR("Blocked package uninstall failed id: %s ver: %s", packageId.c_str(), blockedVer.c_str()); - } - } - } - } - } else { - LOGERR("Never Locked (mLockCount is 0) id: %s ver: %s", packageId.c_str(), version.c_str()); - result = Core::ERROR_GENERAL; - } - #endif - LOGDBG("id: %s ver: %s lock count:%d", packageId.c_str(), version.c_str(), state.mLockCount); - } else { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); - result = Core::ERROR_BAD_REQUEST; - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (Core::ERROR_NONE == result) - { - recordAndPublishTelemetryData(TELEMETRY_MARKER_CLOSE_TIME, - packageId, - requestTime, - PackageManagerImplementation::PackageFailureErrorCode::ERROR_NONE); - } -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - return result; - } - - Core::hresult PackageManagerImplementation::GetLockedInfo(const string &packageId, const string &version, - string &unpackedPath, Exchange::RuntimeConfig& runtimeConfig, string& gatewayMetadataPath, bool &locked) - { - CHECK_CACHE() - Core::hresult result = Core::ERROR_NONE; - - LOGDBG("id: %s ver: %s", packageId.c_str(), version.c_str()); - std::lock_guard lock(mtxState); - auto it = mState.find( { packageId, version } ); - if (it != mState.end()) { - auto &state = it->second; - getRuntimeConfig(state.runtimeConfig, runtimeConfig); - unpackedPath = state.unpackedPath; - locked = (state.mLockCount > 0); - LOGDBG("id: %s ver: %s lock count:%d", packageId.c_str(), version.c_str(), state.mLockCount); - } else { - LOGERR("Package: %s Version: %s Not found", packageId.c_str(), version.c_str()); - result = Core::ERROR_BAD_REQUEST; - } - return result; - } - - Core::hresult PackageManagerImplementation::GetConfigForPackage(const string &fileLocator, string& id, string &version, Exchange::RuntimeConfig& config) - { - CHECK_CACHE() - Core::hresult result = Core::ERROR_GENERAL; - - if (fileLocator.empty()) - { - return Core::ERROR_INVALID_SIGNATURE; - } - - #if defined(USE_LIBPACKAGE) || defined(UNIT_TEST) - packagemanager::ConfigMetaData metadata; - packagemanager::Result pmResult = packageImpl->GetFileMetadata(fileLocator, id, version, metadata); - if (pmResult == packagemanager::SUCCESS) - { - getRuntimeConfig(metadata, config); - result = Core::ERROR_NONE; - } - #endif - return result; - } - - // Internal functions - void PackageManagerImplementation::InitializeState() - { - LOGDBG("entry"); - #ifndef UNIT_TEST - PluginHost::ISubSystem* subSystem = mCurrentservice->SubSystems(); - if (subSystem != nullptr) { - subSystem->Set(PluginHost::ISubSystem::NOT_INSTALLATION, nullptr); - } - #endif - - #if defined (USE_LIBPACKAGE) || defined(UNIT_TEST) - - #if defined (USE_LIBPACKAGE) - packageImpl = packagemanager::IPackageImpl::instance(); - #elif defined(UNIT_TEST) - packageImpl = packagemanager::IPackageImplDummy::instance(); - #endif - - packagemanager::ConfigMetadataArray aConfigMetadata; - packagemanager::Result pmResult = packageImpl->Initialize(configStr, aConfigMetadata); - LOGDBG("aConfigMetadata.count:%zu pmResult=%d", aConfigMetadata.size(), pmResult); - std::lock_guard lock(mtxState); - for (auto it = aConfigMetadata.begin(); it != aConfigMetadata.end(); ++it ) { - StateKey key = it->first; - State state(it->second); - state.installState = InstallState::INSTALLED; - mState.insert( { key, state } ); - } - #endif - - #ifndef UNIT_TEST - if (subSystem != nullptr) { - subSystem->Set(PluginHost::ISubSystem::INSTALLATION, nullptr); - } - #endif - cacheInitialized = true; - const std::string markerFile = PACKAGE_MANAGER_MARKER_FILE; - std::ofstream file(markerFile); - if (file.is_open()) { - file << "PackageManager initialized successfully\n"; - file.close(); - LOGINFO("Marker file created: %s", markerFile.c_str()); - } else { - LOGERR("Failed to create marker file: %s", markerFile.c_str()); - } - LOGDBG("exit"); - } - - void PackageManagerImplementation::downloader(int n) - { - InitializeState(); - while(!done) { - auto di = getNext(); - if (di == nullptr) { - LOGTRACE("Waiting ... "); - std::unique_lock lock(mMutex); - cv.wait(lock, [this] { return done || (mDownloadQueue.size() > 0); }); - } else { - HttpClient::Status status = HttpClient::Status::Success; - int waitTime = 1; - for (int i = 0; i < di->GetRetries(); i++) { - if (i) { - waitTime = nextRetryDuration(waitTime); - LOGDBG("waitTime=%d retry %d/%d", waitTime, i, di->GetRetries()); - std::this_thread::sleep_for(std::chrono::seconds(waitTime)); - // XXX: retrying because of server error, Cancel ?! - if (di->Cancelled()) { - break; - } - } - LOGDBG("Downloading id=%s url=%s file=%s rateLimit=%ld", - di->GetId().c_str(), di->GetUrl().c_str(), di->GetFileLocator().c_str(), di->GetRateLimit()); - std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); - status = mHttpClient->downloadFile(di->GetUrl(), di->GetFileLocator(), di->GetRateLimit()); - std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(end - begin).count(); - if (elapsed) { - /*LOGDBG("Download status=%d code=%ld time=%ld ms", status, - mHttpClient->getStatusCode(), - elapsed);*/ - } - if ( status == HttpClient::Status::Success || mHttpClient->getStatusCode() == 404) { // XXX: other status codes - break; - } - } - - if (mHttpClient->getStatusCode() == 404) { - status = HttpClient::Status::HttpError; - } - DownloadReason reason = DownloadReason::NONE; - switch (status) { - case HttpClient::Status::DiskError: reason = DownloadReason::DISK_PERSISTENCE_FAILURE; break; - case HttpClient::Status::HttpError: reason = DownloadReason::DOWNLOAD_FAILURE; break; - default: break; /* Do nothing */ - } - NotifyDownloadStatus(di->GetId(), di->GetFileLocator(), reason); - mInprogressDownload.reset(); - } - } - } - - Core::hresult PackageManagerImplementation::Install(const string &packageId, const string &version, - const packagemanager::NameValues &keyValues, const string &fileLocator, - State& state - ) - { - Core::hresult result = Core::ERROR_GENERAL; - - if (nullptr == mStorageManagerObject) { // XXX: Delayed instantiation is a bad idea - if (Core::ERROR_NONE != createStorageManagerObject()) { - LOGERR("Failed to create StorageManager"); - } - } - ASSERT (nullptr != mStorageManagerObject); - if (nullptr != mStorageManagerObject) { - string path = ""; - string errorReason = ""; - if(mStorageManagerObject->CreateStorage(packageId, STORAGE_MAX_SIZE, path, errorReason) == Core::ERROR_NONE) { - LOGINFO("CreateStorage path [%s]", path.c_str()); - #if defined(USE_LIBPACKAGE) || defined(UNIT_TEST) - packagemanager::ConfigMetaData config; - packagemanager::Result pmResult = packageImpl->Install(packageId, version, keyValues, fileLocator, config); - if (pmResult == packagemanager::SUCCESS) { - result = Core::ERROR_NONE; - state.installState = InstallState::INSTALLED; - } else { - state.installState = InstallState::INSTALL_FAILURE; - state.failReason = (pmResult == packagemanager::Result::VERSION_MISMATCH) ? - FailReason::PACKAGE_MISMATCH_FAILURE : FailReason::SIGNATURE_VERIFICATION_FAILURE; - LOGERR("Install failed reason %s", getFailReason(state.failReason).c_str()); - } - LOGDBG("Package: %s Version: %s result=%d", packageId.c_str(), version.c_str(), result); - NotifyInstallStatus(packageId, version, state); - #endif - } else { - LOGERR("CreateStorage failed with result :%d errorReason [%s]", result, errorReason.c_str()); - state.failReason = FailReason::PERSISTENCE_FAILURE; - } - } - - return result; - } - - void PackageManagerImplementation::NotifyDownloadStatus(const string& id, const string& locator, const DownloadReason reason) - { - - std::list packageInfoList; - Exchange::IPackageDownloader::PackageInfo packageInfo; - packageInfo.downloadId = id; - packageInfo.fileLocator = locator; - packageInfo.reason = reason; - packageInfoList.emplace_back(packageInfo); - - Exchange::IPackageDownloader::IPackageInfoIterator* packageInfoIterator = Core::Service>::Create(packageInfoList); - - mAdminLock.Lock(); - for (auto notification: mDownloaderNotifications) { - notification->OnAppDownloadStatus(packageInfoIterator); - LOGTRACE(); - } - mAdminLock.Unlock(); - } - - void PackageManagerImplementation::NotifyInstallStatus(const string& id, const string& version, const State &state) - { - JsonArray list = JsonArray(); - JsonObject obj; - obj["packageId"] = id; - obj["version"] = version; - obj["state"] = getInstallState(state.installState); - if (!((state.installState == InstallState::INSTALLED) || (state.installState == InstallState::UNINSTALLED) || - (state.installState == InstallState::INSTALLING) || (state.installState == InstallState::UNINSTALLING))) { - obj["failReason"] = getFailReason(state.failReason); - } - list.Add(obj); - std::string jsonstr; - if (!list.ToString(jsonstr)) { - LOGERR("Failed to stringify JsonArray"); - } - - LOGDBG("id: '%s; ver: '%s' state: %s", id.c_str(), version.c_str(), getInstallState(state.installState).c_str()); - mAdminLock.Lock(); - for (auto notification: mInstallNotifications) { - notification->OnAppInstallationStatus(jsonstr); - LOGTRACE(); - } - mAdminLock.Unlock(); - } - - PackageManagerImplementation::DownloadInfoPtr PackageManagerImplementation::getNext() - { - std::lock_guard lock(mMutex); - LOGTRACE("mDownloadQueue.size = %ld\n", mDownloadQueue.size()); - if (!mDownloadQueue.empty() && mInprogressDownload == nullptr) { - mInprogressDownload = mDownloadQueue.front(); - mDownloadQueue.pop_front(); - } - return mInprogressDownload; - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PackageManager/PackageManagerImplementation.h b/PackageManager/PackageManagerImplementation.h deleted file mode 100644 index b7ff94c..0000000 --- a/PackageManager/PackageManagerImplementation.h +++ /dev/null @@ -1,322 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef USE_LIBPACKAGE -#include -#elif defined(UNIT_TEST) -#include "IPackageImplDummy.h" -#endif -#include - -#include "Module.h" -#include "UtilsLogging.h" -#include -#include - -#include "HttpClient.h" - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include - -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#define TELEMETRY_MARKER_CLOSE_TIME "AppCloseTime_split" -#define TELEMETRY_MARKER_INSTALL_TIME "InstallTime_split" -#define TELEMETRY_MARKER_INSTALL_ERROR "InstallError_split" -#define TELEMETRY_MARKER_UNINSTALL_TIME "UninstallTime_split" -#define TELEMETRY_MARKER_UNINSTALL_ERROR "UninstallError_split" -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - -#define PACKAGE_MANAGER_MARKER_FILE "/tmp/package_manager_ready" - -namespace WPEFramework { -namespace Plugin { - typedef Exchange::IPackageDownloader::Reason DownloadReason; - typedef Exchange::IPackageInstaller::InstallState InstallState; - typedef Exchange::IPackageInstaller::FailReason FailReason; - - class PackageManagerImplementation - : public Exchange::IPackageDownloader - , public Exchange::IPackageInstaller - , public Exchange::IPackageHandler - { - private: - class State { - class BlockedInstallData { - public: - string version; - packagemanager::NameValues keyValues; - string fileLocator; - }; - - public: - State() {} - State(const packagemanager::ConfigMetaData &config) { - PackageManagerImplementation::getRuntimeConfig(config, runtimeConfig); - } - InstallState installState = InstallState::UNINSTALLED; - bool preInsalled = false; - uint32_t mLockCount = 0; - Exchange::RuntimeConfig runtimeConfig; - string gatewayMetadataPath; - string unpackedPath; - FailReason failReason = Exchange::IPackageInstaller::FailReason::NONE; - std::list additionalLocks; - BlockedInstallData blockedInstallData; - - }; - - typedef std::pair StateKey; - typedef std::map StateMap; - - class Configuration : public Core::JSON::Container { - public: - Configuration() - : Core::JSON::Container() - , downloadDir() - { - Add(_T("downloadDir"), &downloadDir); // - } - ~Configuration() = default; - - Configuration(Configuration&&) = delete; - Configuration(const Configuration&) = delete; - Configuration& operator=(Configuration&&) = delete; - Configuration& operator=(const Configuration&) = delete; - - public: - Core::JSON::String downloadDir; - }; - - class DownloadInfo { - const unsigned MIN_RETRIES = 2; - public: - DownloadInfo(const string& url, const string& id, uint8_t retries, long limit) - : id(id) - , url(url) - , priority(false) - , retries(retries ? retries : MIN_RETRIES) - , rateLimit(limit) - , cancel(false) - { - } - - string GetId() { return id; } - string GetUrl() { return url; } - bool GetPriority() { return priority; } - uint8_t GetRetries() { return retries; } - long GetRateLimit() { return rateLimit; } - string GetFileLocator() { return fileLocator; } - void SetFileLocator(string &locator) { fileLocator = locator; } - void Cancel() { cancel = true ;} - bool Cancelled() { return cancel; } - - private: - string id; - string url; - bool priority; - uint8_t retries; - long rateLimit; - string fileLocator; - bool cancel; - }; - - typedef std::shared_ptr DownloadInfoPtr; - typedef std::list DownloadQueue; - - public: -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - enum PackageFailureErrorCode{ - ERROR_NONE, - ERROR_SIGNATURE_VERIFICATION_FAILURE, - ERROR_PACKAGE_MISMATCH_FAILURE, - ERROR_INVALID_METADATA_FAILURE, - ERROR_PERSISTENCE_FAILURE, - ERROR_VERSION_NOT_FOUND - }; -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - PackageManagerImplementation(); - virtual ~PackageManagerImplementation(); - - // IPackageDownloader methods - Core::hresult Download(const string& url, const Exchange::IPackageDownloader::Options &options, Exchange::IPackageDownloader::DownloadId &downloadId) override; - Core::hresult Pause(const string &downloadId) override; - Core::hresult Resume(const string &downloadId) override; - Core::hresult Cancel(const string &downloadId) override; - Core::hresult Delete(const string &fileLocator) override; - Core::hresult Progress(const string &downloadId, Exchange::IPackageDownloader::ProgressInfo &progress); - Core::hresult GetStorageInformation(uint32_t "aKB, uint32_t &usedKB); - Core::hresult RateLimit(const string &downloadId, const uint64_t &limit); - - Core::hresult Register(Exchange::IPackageDownloader::INotification* notification) override; - Core::hresult Unregister(Exchange::IPackageDownloader::INotification* notification) override; - - Core::hresult Initialize(PluginHost::IShell* service) override; - Core::hresult Deinitialize(PluginHost::IShell* service) override; - - // IPackageInstaller methods - Core::hresult Install(const string &packageId, const string &version, IPackageInstaller::IKeyValueIterator* const& additionalMetadata, const string &fileLocator, Exchange::IPackageInstaller::FailReason &failReason) override; - Core::hresult Uninstall(const string &packageId, string &errorReason ) override; - Core::hresult ListPackages(Exchange::IPackageInstaller::IPackageIterator*& packages); - Core::hresult Config(const string &packageId, const string &version, Exchange::RuntimeConfig& configMetadata) override; - Core::hresult PackageState(const string &packageId, const string &version, Exchange::IPackageInstaller::InstallState &state) override; - Core::hresult GetConfigForPackage(const string &fileLocator, string& id, string &version, Exchange::RuntimeConfig& config) override; - - Core::hresult Register(Exchange::IPackageInstaller::INotification *sink) override; - Core::hresult Unregister(Exchange::IPackageInstaller::INotification *sink) override; - - // IPackageHandler methods - Core::hresult Lock(const string &packageId, const string &version, const Exchange::IPackageHandler::LockReason &lockReason, - uint32_t &lockId, string &unpackedPath, Exchange::RuntimeConfig& configMetadata, - Exchange::IPackageHandler::ILockIterator*& appMetadata - ) override; - - Core::hresult Unlock(const string &packageId, const string &version) override; - Core::hresult GetLockedInfo(const string &packageId, const string &version, string &unpackedPath, Exchange::RuntimeConfig& configMetadata, - string& gatewayMetadataPath, bool &locked) override; - - static void getRuntimeConfig(const packagemanager::ConfigMetaData &config, Exchange::RuntimeConfig &runtimeConfig); - static void getRuntimeConfig(const Exchange::RuntimeConfig &config, Exchange::RuntimeConfig &runtimeConfig); - - BEGIN_INTERFACE_MAP(PackageManagerImplementation) - INTERFACE_ENTRY(Exchange::IPackageDownloader) - INTERFACE_ENTRY(Exchange::IPackageInstaller) - INTERFACE_ENTRY(Exchange::IPackageHandler) - END_INTERFACE_MAP - - private: - inline string GetInstalledVersion(const string& id) { - for (auto const& [key, state] : mState) { - if ((id.compare(key.first) == 0) && - (state.installState == InstallState::INSTALLED || state.installState == InstallState::INSTALLATION_BLOCKED || state.installState == InstallState::UNINSTALL_BLOCKED)) { - return key.second; - } - } - return ""; - } - - inline string GetBlockedVersion(const string& id) { - for (auto const& [key, state] : mState) { - if ((id.compare(key.first) == 0) && - (state.installState == InstallState::INSTALLATION_BLOCKED || state.installState == InstallState::UNINSTALL_BLOCKED)) { - return key.second; - } - } - return ""; - } - - inline bool IsInstallBlocked(const string &packageId, const string &version, const packagemanager::NameValues &keyValues, const string &fileLocator); - Core::hresult Install(const string &packageId, const string &version, const packagemanager::NameValues &keyValues, const string &fileLocator, State& state); - - void InitializeState(); - void downloader(int n); - void NotifyDownloadStatus(const string& id, const string& locator, const DownloadReason status); - void NotifyInstallStatus(const string& id, const string& version, const State &state); - - DownloadInfoPtr getNext(); - int nextRetryDuration(int n) { - double nxt = n * (1 + sqrt(5)) / 2.0; - return round(nxt); - } - - string getDownloadReason(DownloadReason reason) { - switch (reason) { - case DownloadReason::DOWNLOAD_FAILURE: return "DOWNLOAD_FAILURE"; - case DownloadReason::DISK_PERSISTENCE_FAILURE: return "DISK_PERSISTENCE_FAILURE"; - default: return "NONE"; - } - } - - string getInstallState(InstallState state) { - switch (state) { - case InstallState::INSTALLING : return "INSTALLING"; - case InstallState::INSTALLATION_BLOCKED : return "INSTALLATION_BLOCKED"; - case InstallState::INSTALL_FAILURE : return "INSTALL_FAILURE"; - case InstallState::INSTALLED : return "INSTALLED"; - case InstallState::UNINSTALLING : return "UNINSTALLING"; - case InstallState::UNINSTALL_FAILURE : return "UNINSTALL_FAILURE"; - case InstallState::UNINSTALLED : return "UNINSTALLED"; - case InstallState::UNINSTALL_BLOCKED : return "UNINSTALL_BLOCKED"; - default: return "Unknown"; - } - } - - string getFailReason(FailReason reason) { - switch (reason) { - case FailReason::SIGNATURE_VERIFICATION_FAILURE : return "SIGNATURE_VERIFICATION_FAILURE"; - case FailReason::PACKAGE_MISMATCH_FAILURE : return "PACKAGE_MISMATCH_FAILURE"; - case FailReason::INVALID_METADATA_FAILURE : return "INVALID_METADATA_FAILURE"; - case FailReason::PERSISTENCE_FAILURE : return "PERSISTENCE_FAILURE"; - default: return "NONE"; - } - } - Core::hresult createStorageManagerObject(); - void releaseStorageManagerObject(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - void recordAndPublishTelemetryData(const std::string& marker, const std::string& appId, time_t requestTime, PackageManagerImplementation::PackageFailureErrorCode errorCode); - time_t getCurrentTimestamp(); -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - - - private: - mutable Core::CriticalSection mAdminLock; - std::list mDownloaderNotifications; - std::list mInstallNotifications; - std::unique_ptr mHttpClient; - - mutable std::mutex mMutex; - std::condition_variable cv; - std::unique_ptr mDownloadThreadPtr; - bool done = false; - DownloadInfoPtr mInprogressDownload; - - uint32_t mNextDownloadId; - DownloadQueue mDownloadQueue; - std::recursive_mutex mtxState; - StateMap mState; - bool cacheInitialized = false; - - std::string downloadDir = "/opt/CDL/"; - string configStr; - - #ifdef USE_LIBPACKAGE - std::shared_ptr packageImpl; - #elif defined(UNIT_TEST) - std::shared_ptr packageImpl; - #endif - PluginHost::IShell* mCurrentservice; - Exchange::IStorageManager* mStorageManagerObject; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - Exchange::ITelemetryMetrics* mTelemetryMetricsObject; -#endif /* ENABLE_AIMANAGERS_TELEMETRY_METRICS */ - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/PackageManager/cmake/FindCurl.cmake b/PackageManager/cmake/FindCurl.cmake deleted file mode 100644 index d9c631b..0000000 --- a/PackageManager/cmake/FindCurl.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# - Try to find curl - -find_path( CURL_INCLUDE_DIR NAMES curl/curl.h ) -#find_library( CURL_LIBRARY NAMES curl libcurl ) -find_library(CURL_LIBRARY NAMES curl) - -include( FindPackageHandleStandardArgs ) - -# Handle the QUIETLY and REQUIRED arguments and set the CURL_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args( Curl DEFAULT_MSG - CURL_LIBRARY CURL_INCLUDE_DIR ) - -mark_as_advanced( CURL_INCLUDE_DIR CURL_LIBRARY ) - -if( CURL_FOUND AND NOT TARGET CURL::libcurl) - set( CURL_LIBRARIES ${CURL_LIBRARY} ) - set( CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR} ) - - add_library( CURL::libcurl SHARED IMPORTED ) - set_target_properties( CURL::libcurl PROPERTIES - IMPORTED_LOCATION "${CURL_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}" ) -endif() diff --git a/PackageManager/cmake/FindJsonCpp.cmake b/PackageManager/cmake/FindJsonCpp.cmake deleted file mode 100644 index 23dd534..0000000 --- a/PackageManager/cmake/FindJsonCpp.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# - Try to find JSONCPP - -find_path( JSONCPP_INCLUDE_DIR NAMES json/json.h PATH_SUFFIXES jsoncpp ) -find_library( JSONCPP_LIBRARY NAMES libjsoncpp.so jsoncpp ) - -include( FindPackageHandleStandardArgs ) - -# Handle the QUIETLY and REQUIRED arguments and set the JSONCPP_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args( JSONCPP DEFAULT_MSG - JSONCPP_LIBRARY JSONCPP_INCLUDE_DIR ) - -mark_as_advanced( JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY ) - -if( JSONCPP_FOUND ) - set( JSONCPP_LIBRARIES ${JSONCPP_LIBRARY} ) - set( JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR} ) -endif() - -if( JSONCPP_FOUND AND NOT TARGET JsonCpp::JsonCpp ) - add_library( JsonCpp::JsonCpp SHARED IMPORTED ) - set_target_properties( JsonCpp::JsonCpp PROPERTIES - IMPORTED_LOCATION "${JSONCPP_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_INCLUDE_DIRS}" ) -endif() \ No newline at end of file diff --git a/PersistentStore/CHANGELOG.md b/PersistentStore/CHANGELOG.md deleted file mode 100644 index 21abee4..0000000 --- a/PersistentStore/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. diff --git a/PersistentStore/CMakeLists.txt b/PersistentStore/CMakeLists.txt deleted file mode 100644 index c832a16..0000000 --- a/PersistentStore/CMakeLists.txt +++ /dev/null @@ -1,78 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -set(PLUGIN_NAME PersistentStore) -find_package(WPEFramework NAMES WPEFramework Thunder) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(CMAKE_CXX_STANDARD 11) - -set(PLUGIN_PERSISTENTSTORE_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_PERSISTENTSTORE_PATH "/opt/secure/persistent/rdkservicestore" CACHE STRING "Path") -set(PLUGIN_PERSISTENTSTORE_LEGACYPATH "/opt/persistent/rdkservicestore" CACHE STRING "Previously used path") -set(PLUGIN_PERSISTENTSTORE_KEY "" CACHE STRING "Encryption key") -set(PLUGIN_PERSISTENTSTORE_MAXSIZE "1000000" CACHE STRING "For all text data, in bytes") -set(PLUGIN_PERSISTENTSTORE_MAXVALUE "10000" CACHE STRING "For single text data, in bytes") -set(PLUGIN_PERSISTENTSTORE_LIMIT "50000" CACHE STRING "Default for all text data in namespace, in bytes") -set(PLUGIN_PERSISTENTSTORE_STARTUPORDER "" CACHE STRING "To configure startup order of PersistentStore plugin") - -add_library(${MODULE_NAME} SHARED - PersistentStore.cpp - PersistentStoreJsonRpc.cpp - Module.cpp -) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -target_link_libraries(${MODULE_NAME} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) -add_library(${PLUGIN_IMPLEMENTATION} SHARED - Module.cpp - PersistentStoreImplementation.cpp -) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -find_package(PkgConfig REQUIRED) -pkg_search_module(SQLITE REQUIRED sqlite3) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${SQLITE_LIBRARIES}) - -find_library(IARMBUS_LIBRARIES NAMES IARMBus) -if (IARMBUS_LIBRARIES) - find_path(IARMBUS_INCLUDE_DIRS NAMES libIBus.h PATH_SUFFIXES rdk/iarmbus REQUIRED) - find_path(IARMSYS_INCLUDE_DIRS NAMES sysMgr.h PATH_SUFFIXES rdk/iarmmgrs/sysmgr REQUIRED) - target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS} ${IARMSYS_INCLUDE_DIRS}) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_LIBRARIES}) - target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE WITH_SYSMGR) -endif () - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/PersistentStore/Module.cpp b/PersistentStore/Module.cpp deleted file mode 100644 index ce759b6..0000000 --- a/PersistentStore/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/PersistentStore/Module.h b/PersistentStore/Module.h deleted file mode 100644 index 30385e8..0000000 --- a/PersistentStore/Module.h +++ /dev/null @@ -1,36 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_PersistentStore -#endif - -#include - -#define PATH_ENV "PERSISTENTSTORE_PATH" -#define MAXSIZE_ENV "PERSISTENTSTORE_MAXSIZE" -#define MAXVALUE_ENV "PERSISTENTSTORE_MAXVALUE" -#define LIMIT_ENV "PERSISTENTSTORE_LIMIT" -#define IARM_INIT_NAME "Thunder_Plugins" -#define IARM_TIMEOUT 1000 -#define SQLITE_TIMEOUT 1000 - -#undef EXTERNAL -#define EXTERNAL diff --git a/PersistentStore/PersistentStore.conf.in b/PersistentStore/PersistentStore.conf.in deleted file mode 100644 index 2202286..0000000 --- a/PersistentStore/PersistentStore.conf.in +++ /dev/null @@ -1,17 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.PersistentStore" -startuporder = "@PLUGIN_PERSISTENTSTORE_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_PERSISTENTSTORE_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) - -configuration.add("path", "@PLUGIN_PERSISTENTSTORE_PATH@") -configuration.add("legacypath", "@PLUGIN_PERSISTENTSTORE_LEGACYPATH@") -configuration.add("key", "@PLUGIN_PERSISTENTSTORE_KEY@") -configuration.add("maxsize", "@PLUGIN_PERSISTENTSTORE_MAXSIZE@") -configuration.add("maxvalue", "@PLUGIN_PERSISTENTSTORE_MAXVALUE@") -configuration.add("limit", "@PLUGIN_PERSISTENTSTORE_LIMIT@") diff --git a/PersistentStore/PersistentStore.config b/PersistentStore/PersistentStore.config deleted file mode 100644 index 510372c..0000000 --- a/PersistentStore/PersistentStore.config +++ /dev/null @@ -1,22 +0,0 @@ -set(autostart true) -set(preconditions Platform) -set(callsign "org.rdk.PersistentStore") - -if(PLUGIN_PERSISTENTSTORE_STARTUPORDER) -set (startuporder ${PLUGIN_PERSISTENTSTORE_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_PERSISTENTSTORE_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() - kv(path ${PLUGIN_PERSISTENTSTORE_PATH}) - kv(legacypath ${PLUGIN_PERSISTENTSTORE_LEGACYPATH}) - kv(key ${PLUGIN_PERSISTENTSTORE_KEY}) - kv(maxsize ${PLUGIN_PERSISTENTSTORE_MAXSIZE}) - kv(maxvalue ${PLUGIN_PERSISTENTSTORE_MAXVALUE}) - kv(limit ${PLUGIN_PERSISTENTSTORE_LIMIT}) -end() -ans(configuration) diff --git a/PersistentStore/PersistentStore.cpp b/PersistentStore/PersistentStore.cpp deleted file mode 100644 index fb9f5fa..0000000 --- a/PersistentStore/PersistentStore.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PersistentStore.h" -#include - -#define API_VERSION_NUMBER_MAJOR 2 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 6 - -namespace WPEFramework { - -namespace Plugin { - - namespace { - - static Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {}); - } - - SERVICE_REGISTRATION(PersistentStore, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - const string PersistentStore::Initialize(PluginHost::IShell* service) - { - string result; - - ASSERT(service != nullptr); - ASSERT(_store == nullptr); - ASSERT(_store2 == nullptr); - ASSERT(_storeCache == nullptr); - ASSERT(_storeInspector == nullptr); - ASSERT(_storeLimit == nullptr); - ASSERT(_service == nullptr); - ASSERT(_connectionId == 0); - - SYSLOG(Logging::Startup, (_T("PersistentStore::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - - auto configLine = _service->ConfigLine(); - _config.FromString(configLine); - - { - Core::File file(_config.Path.Value()); - Core::File oldFile(_config.LegacyPath.Value()); - if (file.Name() != oldFile.Name()) { - if (oldFile.Exists()) { - if (!file.Exists()) { - std::ifstream in(oldFile.Name(), std::ios::in | std::ios::binary); - std::ofstream out(file.Name(), std::ios::out | std::ios::binary); - out << in.rdbuf(); - } - - oldFile.Destroy(); - } - } - } - - Core::SystemInfo::SetEnvironment(PATH_ENV, _config.Path.Value()); - Core::SystemInfo::SetEnvironment(MAXSIZE_ENV, std::to_string(_config.MaxSize.Value())); - Core::SystemInfo::SetEnvironment(MAXVALUE_ENV, std::to_string(_config.MaxValue.Value())); - Core::SystemInfo::SetEnvironment(LIMIT_ENV, std::to_string(_config.Limit.Value())); - - _service->Register(&_notification); - - _store = _service->Root(_connectionId, RPC::CommunicationTimeOut, _T("PersistentStoreImplementation")); - if (_store != nullptr) { - _store2 = _store->QueryInterface(); - if (_store2 != nullptr) { - _store2->Register(&_store2Sink); - } - _storeCache = _store->QueryInterface(); - _storeInspector = _store->QueryInterface(); - _storeLimit = _store->QueryInterface(); - - ASSERT(_store2 != nullptr); - ASSERT(_storeCache != nullptr); - ASSERT(_storeInspector != nullptr); - ASSERT(_storeLimit != nullptr); - } else { - result = _T("Couldn't create implementation instance"); - } - - return result; - } - - void PersistentStore::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("PersistentStore::Deinitialize")))); - - _service->Unregister(&_notification); - - if (_store != nullptr) { - if (_store2 != nullptr) { - _store2->Unregister(&_store2Sink); - _store2->Release(); - _store2 = nullptr; - } - if (_storeCache != nullptr) { - _storeCache->Release(); - _storeCache = nullptr; - } - if (_storeInspector != nullptr) { - _storeInspector->Release(); - _storeInspector = nullptr; - } - if (_storeLimit != nullptr) { - _storeLimit->Release(); - _storeLimit = nullptr; - } - - auto connection = _service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED auto result = _store->Release(); - _store = nullptr; - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if (connection != nullptr) { - connection->Terminate(); - connection->Release(); - } - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("PersistentStore de-initialised")))); - } - - string PersistentStore::Information() const - { - return (string()); - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/PersistentStore.h b/PersistentStore/PersistentStore.h deleted file mode 100644 index f07008d..0000000 --- a/PersistentStore/PersistentStore.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class PersistentStore : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - class Config : public Core::JSON::Container { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - public: - Config() - : Core::JSON::Container() - , MaxSize(0) - , MaxValue(0) - , Limit(0) - { - Add(_T("path"), &Path); - Add(_T("legacypath"), &LegacyPath); - Add(_T("key"), &Key); - Add(_T("maxsize"), &MaxSize); - Add(_T("maxvalue"), &MaxValue); - Add(_T("limit"), &Limit); - } - - public: - Core::JSON::String Path; - Core::JSON::String LegacyPath; - Core::JSON::String Key; - Core::JSON::DecUInt64 MaxSize; - Core::JSON::DecUInt64 MaxValue; - Core::JSON::DecUInt64 Limit; - }; - - class Store2Notification : public Exchange::IStore2::INotification { - private: - Store2Notification(const Store2Notification&) = delete; - Store2Notification& operator=(const Store2Notification&) = delete; - - public: - explicit Store2Notification(PersistentStore& parent) - : _parent(parent) - { - } - ~Store2Notification() override = default; - - public: - void ValueChanged(const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value) override - { - JsonData::PersistentStore::SetValueParamsData params; - params.Scope = JsonData::PersistentStore::ScopeType(scope); - params.Namespace = ns; - params.Key = key; - params.Value = value; - - _parent.event_onValueChanged(params); - } - - BEGIN_INTERFACE_MAP(Store2Notification) - INTERFACE_ENTRY(Exchange::IStore2::INotification) - END_INTERFACE_MAP - - private: - PersistentStore& _parent; - }; - - class RemoteConnectionNotification : public RPC::IRemoteConnection::INotification { - private: - RemoteConnectionNotification() = delete; - RemoteConnectionNotification(const RemoteConnectionNotification&) = delete; - RemoteConnectionNotification& operator=(const RemoteConnectionNotification&) = delete; - - public: - explicit RemoteConnectionNotification(PersistentStore& parent) - : _parent(parent) - { - } - ~RemoteConnectionNotification() override = default; - - BEGIN_INTERFACE_MAP(RemoteConnectionNotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - } - void Deactivated(RPC::IRemoteConnection* connection) override - { - if (connection->Id() == _parent._connectionId) { - ASSERT(_parent._service != nullptr); - Core::IWorkerPool::Instance().Schedule( - Core::Time::Now(), - PluginHost::IShell::Job::Create( - _parent._service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - private: - PersistentStore& _parent; - }; - - private: - PersistentStore(const PersistentStore&) = delete; - PersistentStore& operator=(const PersistentStore&) = delete; - - public: - PersistentStore() - : PluginHost::JSONRPC() - , _service(nullptr) - , _connectionId(0) - , _store(nullptr) - , _store2(nullptr) - , _storeCache(nullptr) - , _storeInspector(nullptr) - , _storeLimit(nullptr) - , _store2Sink(*this) - , _notification(*this) - { - RegisterAll(); - } - ~PersistentStore() override - { - UnregisterAll(); - } - - BEGIN_INTERFACE_MAP(PersistentStore) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IStore, _store) - INTERFACE_AGGREGATE(Exchange::IStore2, _store2) - INTERFACE_AGGREGATE(Exchange::IStoreCache, _storeCache) - INTERFACE_AGGREGATE(Exchange::IStoreInspector, _storeInspector) - INTERFACE_AGGREGATE(Exchange::IStoreLimit, _storeLimit) - END_INTERFACE_MAP - - public: - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void RegisterAll(); - void UnregisterAll(); - - uint32_t endpoint_setValue(const JsonData::PersistentStore::SetValueParamsData& params, JsonData::PersistentStore::DeleteKeyResultInfo& response); - uint32_t endpoint_getValue(const JsonData::PersistentStore::DeleteKeyParamsInfo& params, JsonData::PersistentStore::GetValueResultData& response); - uint32_t endpoint_deleteKey(const JsonData::PersistentStore::DeleteKeyParamsInfo& params, JsonData::PersistentStore::DeleteKeyResultInfo& response); - uint32_t endpoint_deleteNamespace(const JsonData::PersistentStore::DeleteNamespaceParamsInfo& params, JsonData::PersistentStore::DeleteKeyResultInfo& response); - uint32_t endpoint_getKeys(const JsonData::PersistentStore::DeleteNamespaceParamsInfo& params, JsonData::PersistentStore::GetKeysResultData& response); - uint32_t endpoint_getNamespaces(const JsonData::PersistentStore::GetNamespacesParamsInfo& params, JsonData::PersistentStore::GetNamespacesResultData& response); - uint32_t endpoint_getStorageSize(const JsonData::PersistentStore::GetNamespacesParamsInfo& params, JsonObject& response); // Deprecated - uint32_t endpoint_getStorageSizes(const JsonData::PersistentStore::GetNamespacesParamsInfo& params, JsonData::PersistentStore::GetStorageSizesResultData& response); - uint32_t endpoint_flushCache(JsonData::PersistentStore::DeleteKeyResultInfo& response); - uint32_t endpoint_getNamespaceStorageLimit(const JsonData::PersistentStore::DeleteNamespaceParamsInfo& params, JsonData::PersistentStore::GetNamespaceStorageLimitResultData& response); - uint32_t endpoint_setNamespaceStorageLimit(const JsonData::PersistentStore::SetNamespaceStorageLimitParamsData& params); - - void event_onValueChanged(const JsonData::PersistentStore::SetValueParamsData& params) - { - Notify(_T("onValueChanged"), params); - } - - private: - Config _config; - PluginHost::IShell* _service; - uint32_t _connectionId; - Exchange::IStore* _store; - Exchange::IStore2* _store2; - Exchange::IStoreCache* _storeCache; - Exchange::IStoreInspector* _storeInspector; - Exchange::IStoreLimit* _storeLimit; - Core::Sink _store2Sink; - Core::Sink _notification; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/PersistentStoreImplementation.cpp b/PersistentStore/PersistentStoreImplementation.cpp deleted file mode 100644 index a0804ae..0000000 --- a/PersistentStore/PersistentStoreImplementation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PersistentStoreImplementation.h" -#include "sqlite/Store2.h" - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(PersistentStoreImplementation, 1, 0); - - PersistentStoreImplementation::PersistentStoreImplementation() - : _deviceStore2(Core::Service::Create()) - , _deviceStoreCache(nullptr) - , _deviceStoreInspector(nullptr) - , _deviceStoreLimit(nullptr) - , _store2Sink(*this) - { - if (_deviceStore2 != nullptr) { - _deviceStore2->Register(&_store2Sink); - _deviceStoreCache = _deviceStore2->QueryInterface(); - _deviceStoreInspector = _deviceStore2->QueryInterface(); - _deviceStoreLimit = _deviceStore2->QueryInterface(); - } - - ASSERT(_deviceStore2 != nullptr); - ASSERT(_deviceStoreCache != nullptr); - ASSERT(_deviceStoreInspector != nullptr); - ASSERT(_deviceStoreLimit != nullptr); - } - - PersistentStoreImplementation::~PersistentStoreImplementation() - { - if (_deviceStore2 != nullptr) { - _deviceStore2->Unregister(&_store2Sink); - _deviceStore2->Release(); - _deviceStore2 = nullptr; - } - if (_deviceStoreCache != nullptr) { - _deviceStoreCache->Release(); - _deviceStoreCache = nullptr; - } - if (_deviceStoreInspector != nullptr) { - _deviceStoreInspector->Release(); - _deviceStoreInspector = nullptr; - } - if (_deviceStoreLimit != nullptr) { - _deviceStoreLimit->Release(); - _deviceStoreLimit = nullptr; - } - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/PersistentStoreImplementation.h b/PersistentStore/PersistentStoreImplementation.h deleted file mode 100644 index 52c8d56..0000000 --- a/PersistentStore/PersistentStoreImplementation.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class PersistentStoreImplementation : public Exchange::IStore, - public Exchange::IStore2, - public Exchange::IStoreCache, - public Exchange::IStoreInspector, - public Exchange::IStoreLimit { - private: - class Store2Notification : public IStore2::INotification { - private: - Store2Notification(const Store2Notification&) = delete; - Store2Notification& operator=(const Store2Notification&) = delete; - - public: - explicit Store2Notification(PersistentStoreImplementation& parent) - : _parent(parent) - { - } - ~Store2Notification() override = default; - - public: - void ValueChanged(const IStore2::ScopeType scope, const string& ns, const string& key, const string& value) override - { - ASSERT(scope == IStore2::ScopeType::DEVICE); - - Core::SafeSyncType lock(_parent._clientLock); - - std::list::iterator - index(_parent._clients.begin()); - - while (index != _parent._clients.end()) { - (*index)->ValueChanged(ns, key, value); - index++; - } - } - - BEGIN_INTERFACE_MAP(Store) - INTERFACE_ENTRY(IStore2::INotification) - END_INTERFACE_MAP - - private: - PersistentStoreImplementation& _parent; - }; - - private: - PersistentStoreImplementation(const PersistentStoreImplementation&) = delete; - PersistentStoreImplementation& operator=(const PersistentStoreImplementation&) = delete; - - public: - PersistentStoreImplementation(); - ~PersistentStoreImplementation() override; - - BEGIN_INTERFACE_MAP(PersistentStoreImplementation) - INTERFACE_ENTRY(IStore) - INTERFACE_ENTRY(IStore2) - INTERFACE_ENTRY(IStoreCache) - INTERFACE_ENTRY(IStoreInspector) - INTERFACE_ENTRY(IStoreLimit) - END_INTERFACE_MAP - - private: - uint32_t Register(IStore::INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - ASSERT(std::find(_clients.begin(), _clients.end(), notification) == _clients.end()); - - notification->AddRef(); - _clients.push_back(notification); - - return Core::ERROR_NONE; - } - uint32_t Unregister(IStore::INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - std::list::iterator - index(std::find(_clients.begin(), _clients.end(), notification)); - - ASSERT(index != _clients.end()); - - if (index != _clients.end()) { - notification->Release(); - _clients.erase(index); - } - - return Core::ERROR_NONE; - } - uint32_t SetValue(const string& ns, const string& key, const string& value) override - { - return SetValue(IStore2::ScopeType::DEVICE, ns, key, value, 0); - } - uint32_t GetValue(const string& ns, const string& key, string& value) override - { - uint32_t ttl; - return GetValue(IStore2::ScopeType::DEVICE, ns, key, value, ttl); - } - uint32_t DeleteKey(const string& ns, const string& key) override - { - return DeleteKey(IStore2::ScopeType::DEVICE, ns, key); - } - uint32_t DeleteNamespace(const string& ns) override - { - return DeleteNamespace(IStore2::ScopeType::DEVICE, ns); - } - uint32_t Register(IStore2::INotification* notification) override - { - if (_deviceStore2 != nullptr) { - _deviceStore2->Register(notification); - } - return Core::ERROR_NONE; - } - uint32_t Unregister(IStore2::INotification* notification) override - { - if (_deviceStore2 != nullptr) { - _deviceStore2->Unregister(notification); - } - return Core::ERROR_NONE; - } - uint32_t SetValue(const IStore2::ScopeType, const string& ns, const string& key, const string& value, const uint32_t ttl) override - { - if (_deviceStore2 != nullptr) { - return _deviceStore2->SetValue(IStore2::ScopeType::DEVICE, ns, key, value, ttl); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetValue(const IStore2::ScopeType, const string& ns, const string& key, string& value, uint32_t& ttl) override - { - if (_deviceStore2 != nullptr) { - return _deviceStore2->GetValue(IStore2::ScopeType::DEVICE, ns, key, value, ttl); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t DeleteKey(const IStore2::ScopeType, const string& ns, const string& key) override - { - if (_deviceStore2 != nullptr) { - return _deviceStore2->DeleteKey(IStore2::ScopeType::DEVICE, ns, key); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t DeleteNamespace(const IStore2::ScopeType, const string& ns) override - { - if (_deviceStore2 != nullptr) { - return _deviceStore2->DeleteNamespace(IStore2::ScopeType::DEVICE, ns); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t FlushCache() override - { - if (_deviceStoreCache != nullptr) { - return _deviceStoreCache->FlushCache(); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetKeys(const IStoreInspector::ScopeType, const string& ns, RPC::IStringIterator*& keys) override - { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetKeys(IStore2::ScopeType::DEVICE, ns, keys); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetNamespaces(const IStoreInspector::ScopeType, RPC::IStringIterator*& namespaces) override - { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetNamespaces(IStore2::ScopeType::DEVICE, namespaces); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetStorageSizes(const IStoreInspector::ScopeType, INamespaceSizeIterator*& storageList) override - { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetStorageSizes(IStore2::ScopeType::DEVICE, storageList); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t SetNamespaceStorageLimit(const IStoreLimit::ScopeType, const string& ns, const uint32_t size) override - { - if (_deviceStoreLimit != nullptr) { - return _deviceStoreLimit->SetNamespaceStorageLimit(IStore2::ScopeType::DEVICE, ns, size); - } - return Core::ERROR_NOT_SUPPORTED; - } - uint32_t GetNamespaceStorageLimit(const IStoreLimit::ScopeType, const string& ns, uint32_t& size) override - { - if (_deviceStoreLimit != nullptr) { - return _deviceStoreLimit->GetNamespaceStorageLimit(IStore2::ScopeType::DEVICE, ns, size); - } - return Core::ERROR_NOT_SUPPORTED; - } - - private: - IStore2* _deviceStore2; - IStoreCache* _deviceStoreCache; - IStoreInspector* _deviceStoreInspector; - IStoreLimit* _deviceStoreLimit; - Core::Sink _store2Sink; - std::list _clients; - Core::CriticalSection _clientLock; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/PersistentStoreJsonRpc.cpp b/PersistentStore/PersistentStoreJsonRpc.cpp deleted file mode 100644 index a3b2858..0000000 --- a/PersistentStore/PersistentStoreJsonRpc.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PersistentStore.h" - -namespace WPEFramework { -namespace Plugin { - - using namespace JsonData::PersistentStore; - - void PersistentStore::RegisterAll() - { - Register(_T("setValue"), &PersistentStore::endpoint_setValue, this); - Register(_T("getValue"), &PersistentStore::endpoint_getValue, this); - Register(_T("deleteKey"), &PersistentStore::endpoint_deleteKey, this); - Register(_T("deleteNamespace"), &PersistentStore::endpoint_deleteNamespace, this); - Register(_T("getKeys"), &PersistentStore::endpoint_getKeys, this); - Register(_T("getNamespaces"), &PersistentStore::endpoint_getNamespaces, this); - Register(_T("getStorageSize"), &PersistentStore::endpoint_getStorageSize, this); // Deprecated - Register(_T("getStorageSizes"), &PersistentStore::endpoint_getStorageSizes, this); - Register(_T("flushCache"), &PersistentStore::endpoint_flushCache, this); - Register(_T("getNamespaceStorageLimit"), &PersistentStore::endpoint_getNamespaceStorageLimit, this); - Register(_T("setNamespaceStorageLimit"), &PersistentStore::endpoint_setNamespaceStorageLimit, this); - } - - void PersistentStore::UnregisterAll() - { - Unregister(_T("setValue")); - Unregister(_T("getValue")); - Unregister(_T("deleteKey")); - Unregister(_T("deleteNamespace")); - Unregister(_T("getKeys")); - Unregister(_T("getNamespaces")); - Unregister(_T("getStorageSize")); - Unregister(_T("getStorageSizes")); - Unregister(_T("flushCache")); - Unregister(_T("getNamespaceStorageLimit")); - Unregister(_T("setNamespaceStorageLimit")); - } - - uint32_t PersistentStore::endpoint_setValue(const SetValueParamsData& params, DeleteKeyResultInfo& response) - { - auto result = _store2->SetValue( - Exchange::IStore2::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - params.Key.Value(), - params.Value.Value(), - params.Ttl.Value()); - if (result == Core::ERROR_NONE) { - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_getValue(const DeleteKeyParamsInfo& params, GetValueResultData& response) - { - string value; - uint32_t ttl; - auto result = _store2->GetValue( - Exchange::IStore2::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - params.Key.Value(), - value, - ttl); - if (result == Core::ERROR_NONE) { - response.Value = value; - if (ttl > 0) { - response.Ttl = ttl; - } - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_deleteKey(const DeleteKeyParamsInfo& params, DeleteKeyResultInfo& response) - { - auto result = _store2->DeleteKey( - Exchange::IStore2::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - params.Key.Value()); - if (result == Core::ERROR_NONE) { - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_deleteNamespace(const DeleteNamespaceParamsInfo& params, DeleteKeyResultInfo& response) - { - auto result = _store2->DeleteNamespace( - Exchange::IStore2::ScopeType(params.Scope.Value()), - params.Namespace.Value()); - if (result == Core::ERROR_NONE) { - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_getKeys(const DeleteNamespaceParamsInfo& params, GetKeysResultData& response) - { - RPC::IStringIterator* it; - auto result = _storeInspector->GetKeys( - Exchange::IStoreInspector::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - it); - if (result == Core::ERROR_NONE) { - string element; - while (it->Next(element) == true) { - response.Keys.Add() = element; - } - it->Release(); - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_getNamespaces(const GetNamespacesParamsInfo& params, GetNamespacesResultData& response) - { - RPC::IStringIterator* it; - auto result = _storeInspector->GetNamespaces( - Exchange::IStoreInspector::ScopeType(params.Scope.Value()), - it); - if (result == Core::ERROR_NONE) { - string element; - while (it->Next(element) == true) { - response.Namespaces.Add() = element; - } - it->Release(); - response.Success = true; - } - - return result; - } - - // Deprecated - uint32_t PersistentStore::endpoint_getStorageSize(const GetNamespacesParamsInfo& params, JsonObject& response) - { - Exchange::IStoreInspector::INamespaceSizeIterator* it; - auto result = _storeInspector->GetStorageSizes( - Exchange::IStoreInspector::ScopeType(params.Scope.Value()), - it); - if (result == Core::ERROR_NONE) { - JsonObject jsonObject; - Exchange::IStoreInspector::NamespaceSize element; - while (it->Next(element) == true) { - jsonObject[element.ns.c_str()] = element.size; - } - it->Release(); - response["namespaceSizes"] = jsonObject; - response["success"] = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_getStorageSizes(const GetNamespacesParamsInfo& params, GetStorageSizesResultData& response) - { - Exchange::IStoreInspector::INamespaceSizeIterator* it; - auto result = _storeInspector->GetStorageSizes( - Exchange::IStoreInspector::ScopeType(params.Scope.Value()), - it); - if (result == Core::ERROR_NONE) { - Exchange::IStoreInspector::NamespaceSize element; - while (it->Next(element) == true) { - auto& item = response.StorageList.Add(); - item.Namespace = element.ns; - item.Size = element.size; - } - it->Release(); - } - - return result; - } - - uint32_t PersistentStore::endpoint_flushCache(DeleteKeyResultInfo& response) - { - auto result = _storeCache->FlushCache(); - if (result == Core::ERROR_NONE) { - response.Success = true; - } - - return result; - } - - uint32_t PersistentStore::endpoint_getNamespaceStorageLimit(const DeleteNamespaceParamsInfo& params, GetNamespaceStorageLimitResultData& response) - { - uint32_t size; - auto result = _storeLimit->GetNamespaceStorageLimit( - Exchange::IStoreLimit::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - size); - if (result == Core::ERROR_NONE) { - response.StorageLimit = size; - } - - return result; - } - - uint32_t PersistentStore::endpoint_setNamespaceStorageLimit(const SetNamespaceStorageLimitParamsData& params) - { - return _storeLimit->SetNamespaceStorageLimit( - Exchange::IStoreLimit::ScopeType(params.Scope.Value()), - params.Namespace.Value(), - params.StorageLimit.Value()); - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/sqlite/Store2.h b/PersistentStore/sqlite/Store2.h deleted file mode 100644 index 14c29a8..0000000 --- a/PersistentStore/sqlite/Store2.h +++ /dev/null @@ -1,658 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "../Module.h" -#include -#include -#include -#ifdef WITH_SYSMGR -#include -#include -#endif - -namespace WPEFramework { -namespace Plugin { - namespace Sqlite { - - class Store2 : public Exchange::IStore2, - public Exchange::IStoreCache, - public Exchange::IStoreInspector, - public Exchange::IStoreLimit { - private: - class Job : public Core::IDispatch { - public: - Job(Store2* parent, const IStore2::ScopeType scope, const string& ns, const string& key, const string& value) - : _parent(parent) - , _scope(scope) - , _ns(ns) - , _key(key) - , _value(value) - { - _parent->AddRef(); - } - ~Job() override - { - _parent->Release(); - } - void Dispatch() override - { - _parent->OnValueChanged(_scope, _ns, _key, _value); - } - - private: - Store2* _parent; - const IStore2::ScopeType _scope; - const string _ns; - const string _key; - const string _value; - }; - - private: - Store2(const Store2&) = delete; - Store2& operator=(const Store2&) = delete; - - public: - Store2() - : Store2( - getenv(PATH_ENV), - std::stoul(getenv(MAXSIZE_ENV)), - std::stoul(getenv(MAXVALUE_ENV)), - std::stoul(getenv(LIMIT_ENV))) - { - } - Store2(const string& path, const uint64_t maxSize, const uint64_t maxValue, const uint64_t limit) - : _path(path) - , _maxSize(maxSize) - , _maxValue(maxValue) - , _limit(limit) - , _data(nullptr) - , _corrupt(false) - { - TempDirectoryCheck(); - IntegrityCheck(); - Backup(); - Open(); - } - ~Store2() override - { - Close(); - } - - private: - void TempDirectoryCheck() - { - Core::File file(_path + "-journal"); - if (file.IsDirectory()) { // It's supposed to be a file - TRACE(Trace::Error, (_T("file system corruption"))); - if (!file.Move(file.Name() + "-old")) { - perror("rename failed"); - } - Core::Directory(file.Name().c_str()).Destroy(); - if (!file.Destroy()) { - perror("remove failed"); - } - } - } - void IntegrityCheck() - { - Core::File file(_path); - if (file.Exists()) { - sqlite3_open(file.Name().c_str(), &_data); - auto rc = sqlite3_exec(_data, - "pragma integrity_check;", 0, 0, 0); - sqlite3_close_v2(_data); - if ((rc == SQLITE_CORRUPT) || (rc == SQLITE_NOTADB)) { - OnError(__FUNCTION__, rc); - if (!file.Destroy()) { - perror("remove failed"); - } - _corrupt = true; - } - } - } - void Backup() - { - Core::File file(_path); - Core::File fileB(_path + "-backup"); - if (_corrupt ? fileB.Exists() : file.Exists()) { - sqlite3* bkp; - sqlite3_open(file.Name().c_str(), &_data); - sqlite3_open(fileB.Name().c_str(), &bkp); - auto to = _corrupt ? _data : bkp, - from = _corrupt ? bkp : _data; - auto ptr = sqlite3_backup_init( - to, "main", from, "main"); - if (ptr != nullptr) { - sqlite3_backup_step(ptr, -1); - auto rc = sqlite3_backup_finish(ptr); - if (rc != SQLITE_OK) { - OnError(__FUNCTION__, rc); - } - } else { - OnError(__FUNCTION__, sqlite3_errcode(to)); - } - sqlite3_close_v2(bkp); - sqlite3_close_v2(_data); - } - } - void Open() - { - Core::File file(_path); - Core::Directory(file.PathName().c_str()).CreatePath(); - auto rc = sqlite3_open(_path.c_str(), &_data); - if (rc != SQLITE_OK) { - OnError(__FUNCTION__, rc); - } - rc = sqlite3_busy_timeout(_data, SQLITE_TIMEOUT); // Timeout - if (rc != SQLITE_OK) { - OnError(__FUNCTION__, rc); - } - const std::vector statements = { - "pragma foreign_keys = on;", - "create table if not exists namespace" - " (id integer primary key,name text unique);", - "create table if not exists item" - " (ns integer,key text,value text," - "foreign key(ns) references namespace(id) on delete cascade on update no action," - "unique(ns,key) on conflict replace);", - "create table if not exists limits" - " (n integer,size integer," - "foreign key(n) references namespace(id) on delete cascade on update no action," - "unique(n) on conflict replace);", - "alter table item add column ttl integer;", - "create temporary trigger if not exists ns_empty insert on namespace" - " begin select case when length(new.name) = 0" - " then raise (fail, 'empty') end; end;", - "create temporary trigger if not exists key_empty insert on item" - " begin select case when length(new.key) = 0" - " then raise (fail, 'empty') end; end;", - "create temporary trigger if not exists ns_maxvalue insert on namespace" - " begin select case when length(new.name) > " - + std::to_string(_maxValue) + " then raise (fail, 'max value') end; end;", - "create temporary trigger if not exists key_maxvalue insert on item" - " begin select case when length(new.key) > " - + std::to_string(_maxValue) + " then raise (fail, 'max value') end; end;", - "create temporary trigger if not exists value_maxvalue insert on item" - " begin select case when length(new.value) > " - + std::to_string(_maxValue) + " then raise (fail, 'max value') end; end;", - "create temporary trigger if not exists ns_maxsize insert on namespace" - " begin select case when" - " (select sum(s) from (select sum(length(key)+length(value)) s from item" - " union all select sum(length(name)) s from namespace" - " union all select length(new.name) s)) > " - + std::to_string(_maxSize) + " then raise (fail, 'max size') end; end;", - "create temporary trigger if not exists item_maxsize insert on item" - " begin select case when" - " (select sum(s) from (select sum(length(key)+length(value)) s from item" - " union all select sum(length(name)) s from namespace" - " union all select length(new.key)+length(new.value) s)) > " - + std::to_string(_maxSize) + " then raise (fail, 'max size') end; end;", - "create temporary trigger if not exists item_limit_default insert on item" - " begin select case when" - " (select sum(s) from (select sum(length(key)+length(value)) s from item where ns = new.ns" - " union all select length(new.key)+length(new.value) s)) > " - + std::to_string(_limit) + " then raise (fail, 'limit') end; end;", - "create temporary trigger if not exists item_limit insert on item" - " begin select case when" - " (select size-length(new.key)-length(new.value)-ifnull(sum(length(key)+length(value)), 0) from limits" - " left join item on limits.n = item.ns where n = new.ns) < 0" - " then raise (fail, 'limit') end; end;" - }; - for (auto& sql : statements) { - auto rc = sqlite3_exec(_data, sql.c_str(), nullptr, nullptr, nullptr); - if (rc != SQLITE_OK) { - OnError(__FUNCTION__, rc); - } - } - } - void Close() - { - auto rc = sqlite3_close_v2(_data); - if (rc != SQLITE_OK) { - OnError(__FUNCTION__, rc); - } - } - - private: - bool IsTimeSynced() const - { -#ifdef WITH_SYSMGR - // Get actual state, as it may change at any time... - IARM_Bus_Init(IARM_INIT_NAME); - IARM_Bus_Connect(); - IARM_Bus_SYSMgr_GetSystemStates_Param_t param; - if ((IARM_Bus_Call_with_IPCTimeout( - IARM_BUS_SYSMGR_NAME, - IARM_BUS_SYSMGR_API_GetSystemStates, - ¶m, - sizeof(param), - IARM_TIMEOUT) // Timeout - != IARM_RESULT_SUCCESS) - || !param.time_source.state) { - return false; - } -#endif - return true; - } - - public: - uint32_t Register(INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - ASSERT(std::find(_clients.begin(), _clients.end(), notification) == _clients.end()); - - notification->AddRef(); - _clients.push_back(notification); - - return Core::ERROR_NONE; - } - uint32_t Unregister(INotification* notification) override - { - Core::SafeSyncType lock(_clientLock); - - std::list::iterator - index(std::find(_clients.begin(), _clients.end(), notification)); - - ASSERT(index != _clients.end()); - - if (index != _clients.end()) { - notification->Release(); - _clients.erase(index); - } - - return Core::ERROR_NONE; - } - uint32_t SetValue(const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) override - { - ASSERT(scope == IStore2::ScopeType::DEVICE); - - uint32_t result; - - if (ttl != 0) { - if (!IsTimeSynced()) { - return Core::ERROR_PENDING_CONDITIONS; - } - } - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "insert or ignore into namespace (name) values (?);", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - if (rc == SQLITE_DONE) { - sqlite3_prepare_v2(_data, "insert into item (ns,key,value,ttl)" - " select id, ?, ?, ?" - " from namespace" - " where name = ?" - ";", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, key.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, value.c_str(), -1, SQLITE_TRANSIENT); - if (ttl != 0) { - sqlite3_bind_int64(stmt, 3, (int64_t)ttl + time(nullptr)); - } else { - sqlite3_bind_null(stmt, 3); - } - sqlite3_bind_text(stmt, 4, ns.c_str(), -1, SQLITE_TRANSIENT); - rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - } - - if (rc == SQLITE_DONE) { - Core::IWorkerPool::Instance().Submit(Core::ProxyType( - Core::ProxyType::Create(this, scope, ns, key, value))); // Decouple notification - - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - if (rc == SQLITE_CONSTRAINT) { - result = Core::ERROR_INVALID_INPUT_LENGTH; - } else { - result = Core::ERROR_GENERAL; - } - } - - return result; - } - uint32_t GetValue(const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) override - { - ASSERT(scope == IStore2::ScopeType::DEVICE); - - uint32_t result; - - string k, v; - int64_t t = 0; - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "select key, value, ttl" - " from namespace" - " left join item on (namespace.id = item.ns and key = ?)" - " where name = ?" - ";", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, key.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, ns.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - if (rc == SQLITE_ROW) { - if (sqlite3_column_type(stmt, 0) != SQLITE_NULL) { - k = (const char*)sqlite3_column_text(stmt, 0); - v = (const char*)sqlite3_column_text(stmt, 1); - t = sqlite3_column_int64(stmt, 2); - } - } - sqlite3_finalize(stmt); - - if (rc == SQLITE_ROW) { - if (!k.empty()) { - if (t == 0) { - value = v; - ttl = 0; - result = Core::ERROR_NONE; - } else if (IsTimeSynced()) { - t -= time(nullptr); - if (t > 0) { - value = v; - ttl = t; - result = Core::ERROR_NONE; - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else { - result = Core::ERROR_PENDING_CONDITIONS; - } - - } else { - result = Core::ERROR_UNKNOWN_KEY; - } - } else if (rc == SQLITE_DONE) { - result = Core::ERROR_NOT_EXIST; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t DeleteKey(const IStore2::ScopeType scope, const string& ns, const string& key) override - { - ASSERT(scope == IStore2::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "delete from item" - " where ns in (select id from namespace where name = ?)" - " and key = ?" - ";", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, key.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - - if (rc == SQLITE_DONE) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t DeleteNamespace(const IStore2::ScopeType scope, const string& ns) override - { - ASSERT(scope == IStore2::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "delete from namespace where name = ?;", -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - - if (rc == SQLITE_DONE) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t FlushCache() override - { - uint32_t result; - - auto rc = sqlite3_db_cacheflush(_data); - - if (rc == SQLITE_OK) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - sync(); - - return result; - } - uint32_t GetKeys(const IStoreInspector::ScopeType scope, const string& ns, RPC::IStringIterator*& keys) override - { - ASSERT(scope == IStoreInspector::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "select key" - " from item" - " where ns in (select id from namespace where name = ?)" - ";", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - std::list list; - int rc; - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - list.emplace_back((const char*)sqlite3_column_text(stmt, 0)); - } - sqlite3_finalize(stmt); - - if (rc == SQLITE_DONE) { - keys = (Core::Service::Create(list)); - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t GetNamespaces(const IStoreInspector::ScopeType scope, RPC::IStringIterator*& namespaces) override - { - ASSERT(scope == IStoreInspector::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "select name from namespace;", -1, &stmt, nullptr); - std::list list; - int rc; - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - list.emplace_back((const char*)sqlite3_column_text(stmt, 0)); - } - sqlite3_finalize(stmt); - - if (rc == SQLITE_DONE) { - namespaces = (Core::Service::Create(list)); - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t GetStorageSizes(const IStoreInspector::ScopeType scope, INamespaceSizeIterator*& storageList) override - { - ASSERT(scope == IStoreInspector::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "select name, sum(length(key)+length(value))" - " from item" - " inner join namespace on namespace.id = item.ns" - " group by name" - ";", - -1, &stmt, nullptr); - std::list list; - int rc; - while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { - NamespaceSize namespaceSize; - namespaceSize.ns = (const char*)sqlite3_column_text(stmt, 0); - namespaceSize.size = sqlite3_column_int(stmt, 1); - list.emplace_back(namespaceSize); - } - sqlite3_finalize(stmt); - - if (rc == SQLITE_DONE) { - storageList = (Core::Service>::Create(list)); - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - uint32_t SetNamespaceStorageLimit(const IStoreLimit::ScopeType scope, const string& ns, const uint32_t size) override - { - ASSERT(scope == IStoreLimit::ScopeType::DEVICE); - - uint32_t result; - - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "insert or ignore into namespace (name) values (?);", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - if (rc == SQLITE_DONE) { - sqlite3_prepare_v2(_data, "insert into limits (n,size)" - " select id, ?" - " from namespace" - " where name = ?" - ";", - -1, &stmt, nullptr); - sqlite3_bind_int(stmt, 1, size); - sqlite3_bind_text(stmt, 2, ns.c_str(), -1, SQLITE_TRANSIENT); - rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - } - - if (rc == SQLITE_DONE) { - result = Core::ERROR_NONE; - } else { - OnError(__FUNCTION__, rc); - if (rc == SQLITE_CONSTRAINT) { - result = Core::ERROR_INVALID_INPUT_LENGTH; - } else { - result = Core::ERROR_GENERAL; - } - } - - return result; - } - uint32_t GetNamespaceStorageLimit(const IStoreLimit::ScopeType scope, const string& ns, uint32_t& size) override - { - ASSERT(scope == IStoreLimit::ScopeType::DEVICE); - - uint32_t result; - - uint32_t s; - sqlite3_stmt* stmt; - sqlite3_prepare_v2(_data, "select size" - " from limits" - " inner join namespace on namespace.id = limits.n" - " where name = ?" - ";", - -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, ns.c_str(), -1, SQLITE_TRANSIENT); - auto rc = sqlite3_step(stmt); - if (rc == SQLITE_ROW) { - s = (uint32_t)sqlite3_column_int(stmt, 0); - result = Core::ERROR_NONE; - } - sqlite3_finalize(stmt); - - if (rc == SQLITE_ROW) { - size = s; - result = Core::ERROR_NONE; - } else if (rc == SQLITE_DONE) { - result = Core::ERROR_NOT_EXIST; - } else { - OnError(__FUNCTION__, rc); - result = Core::ERROR_GENERAL; - } - - return result; - } - - BEGIN_INTERFACE_MAP(Store2) - INTERFACE_ENTRY(IStore2) - INTERFACE_ENTRY(IStoreCache) - INTERFACE_ENTRY(IStoreInspector) - INTERFACE_ENTRY(IStoreLimit) - END_INTERFACE_MAP - - private: - void OnValueChanged(const IStore2::ScopeType scope, const string& ns, const string& key, const string& value) - { - Core::SafeSyncType lock(_clientLock); - - std::list::iterator - index(_clients.begin()); - - while (index != _clients.end()) { - // If main process is out of threads, this can time out, and IPC will mess up... - (*index)->ValueChanged(scope, ns, key, value); - index++; - } - } - void OnError(const char* fn, const int status) const - { - TRACE(Trace::Error, (_T("%s sqlite error %d"), fn, status)); - } - - private: - const string _path; - const uint64_t _maxSize; - const uint64_t _maxValue; - const uint64_t _limit; - sqlite3* _data; - std::list _clients; - Core::CriticalSection _clientLock; - bool _corrupt; - }; - - } // namespace Sqlite -} // namespace Plugin -} // namespace WPEFramework diff --git a/PersistentStore/sqlite/l1test/CMakeLists.txt b/PersistentStore/sqlite/l1test/CMakeLists.txt deleted file mode 100644 index dc0f2c5..0000000 --- a/PersistentStore/sqlite/l1test/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -project(sqlitel1test) - -set(CMAKE_CXX_STANDARD 11) - -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG main -) -FetchContent_MakeAvailable(googletest) - -find_package(WPEFramework NAMES WPEFramework Thunder) -find_package(${NAMESPACE}Plugins REQUIRED) - -add_executable(${PROJECT_NAME} - ../../Module.cpp - Store2Test.cpp -) - -target_link_libraries(${PROJECT_NAME} PRIVATE - gmock_main - ${NAMESPACE}Plugins::${NAMESPACE}Plugins -) - -find_package(PkgConfig REQUIRED) -pkg_search_module(SQLITE REQUIRED sqlite3) -target_link_libraries(${PROJECT_NAME} PRIVATE ${SQLITE_LIBRARIES}) - -install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/PersistentStore/sqlite/l1test/Store2NotificationMock.h b/PersistentStore/sqlite/l1test/Store2NotificationMock.h deleted file mode 100644 index 5924a58..0000000 --- a/PersistentStore/sqlite/l1test/Store2NotificationMock.h +++ /dev/null @@ -1,32 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -class Store2NotificationMock : public WPEFramework::Exchange::IStore2::INotification { -public: - ~Store2NotificationMock() override = default; - MOCK_METHOD(void, ValueChanged, (const WPEFramework::Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value), (override)); - BEGIN_INTERFACE_MAP(Store2NotificationMock) - INTERFACE_ENTRY(INotification) - END_INTERFACE_MAP -}; diff --git a/PersistentStore/sqlite/l1test/Store2Test.cpp b/PersistentStore/sqlite/l1test/Store2Test.cpp deleted file mode 100644 index 2fbce86..0000000 --- a/PersistentStore/sqlite/l1test/Store2Test.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include - -#include "../Store2.h" -#include "Store2NotificationMock.h" - -using ::testing::_; -using ::testing::Eq; -using ::testing::Gt; -using ::testing::IsFalse; -using ::testing::IsTrue; -using ::testing::Le; -using ::testing::NiceMock; -using ::testing::NotNull; -using ::testing::Test; -using ::WPEFramework::Exchange::IStore2; -using ::WPEFramework::Exchange::IStoreInspector; -using ::WPEFramework::Exchange::IStoreLimit; -using ::WPEFramework::Plugin::Sqlite::Store2; -using ::WPEFramework::RPC::IStringIterator; - -const auto kPath = "/tmp/persistentstore/sqlite/l1test/store2test"; -const auto kMaxSize = 100; -const auto kMaxValue = 5; -const auto kLimit = 50; -const auto kNewLimit = 10; -const auto kValue = "value"; -const auto kKey = "key"; -const auto kAppId = "app"; -const auto kTtl = 2; -const auto kNoTtl = 0; - -class AStore2 : public Test { -protected: - WPEFramework::Core::ProxyType store2; - - void SetUp() override - { - // Create a WorkerPool with multiple threads - _dispatcher = new WorkerPoolDispatcher(); - _workerPool = new WPEFramework::Core::WorkerPool( - 1, // threadCount - WPEFramework::Core::Thread::DefaultStackSize(), - 2, // queueSize - _dispatcher, - nullptr); - - WPEFramework::Core::IWorkerPool::Assign(_workerPool); - _workerPool->Run(); - - store2 = WPEFramework::Core::ProxyType::Create( - kPath, kMaxSize, kMaxValue, kLimit); - } - void TearDown() override - { - if (_workerPool != nullptr) { - _workerPool->Stop(); - WPEFramework::Core::IWorkerPool::Assign(nullptr); - delete _workerPool; - _workerPool = nullptr; - } - - if (_dispatcher != nullptr) { - delete _dispatcher; - _dispatcher = nullptr; - } - } - - // Simple dispatcher for testing - class WorkerPoolDispatcher - : public WPEFramework::Core::ThreadPool::IDispatcher { - public: - WorkerPoolDispatcher() = default; - ~WorkerPoolDispatcher() override = default; - - void Initialize() override {} - void Deinitialize() override {} - void Dispatch(WPEFramework::Core::IDispatch* job) override - { - job->Dispatch(); - } - }; - - WorkerPoolDispatcher* _dispatcher; - WPEFramework::Core::WorkerPool* _workerPool; -}; - -TEST_F(AStore2, DoesNotSetValueWhenNamespaceEmpty) -{ - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, "", kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetValueWhenKeyEmpty) -{ - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, "", kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetValueWhenNamespaceTooLarge) -{ - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, "this is too large", - kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetValueWhenKeyTooLarge) -{ - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, "this is too large", - kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetValueWhenValueTooLarge) -{ - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, - "this is too large", kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotGetValueWhenNamespaceDoesNotExist) -{ - string value; - uint32_t ttl; - EXPECT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, "none", kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_NOT_EXIST)); -} - -TEST_F(AStore2, DeletesKeyWhenNamespaceDoesNotExist) -{ - EXPECT_THAT(store2->DeleteKey(IStore2::ScopeType::DEVICE, "none", kKey), - Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, DeletesNamespaceWhenNamespaceDoesNotExist) -{ - EXPECT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, "none"), - Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, SetsValueWhenValueEmpty) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, "", kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - string value; - uint32_t ttl; - ASSERT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(value, Eq("")); -} - -TEST_F(AStore2, GetsValueWithTtl) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - string value; - uint32_t ttl; - ASSERT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(value, Eq(kValue)); - EXPECT_THAT(ttl, Le(kTtl)); - EXPECT_THAT(ttl, Gt(0)); -} - -TEST_F(AStore2, DoesNotGetValueWhenTtlExpired) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - WPEFramework::Core::Event lock(false, true); - lock.Lock(kTtl * WPEFramework::Core::Time::MilliSecondsPerSecond); - string value; - uint32_t ttl; - EXPECT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_UNKNOWN_KEY)); -} - -TEST_F(AStore2, SendsValueChangedEventWhenSetValue) -{ - IStore2::ScopeType eventScope; - string eventNamespace; - string eventKey; - string eventValue; - WPEFramework::Core::Event lock(false, true); - WPEFramework::Core::Sink> sink; - EXPECT_CALL(sink, ValueChanged(_, _, _, _)) - .WillRepeatedly( - [&](const IStore2::ScopeType scope, const string& ns, - const string& key, const string& value) { - eventScope = scope; - eventNamespace = ns; - eventKey = key; - eventValue = value; - lock.SetEvent(); - return WPEFramework::Core::ERROR_NONE; - }); - store2->Register(&sink); - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - lock.Lock(); - EXPECT_THAT(eventScope, Eq(IStore2::ScopeType::DEVICE)); - EXPECT_THAT(eventNamespace, Eq(kAppId)); - EXPECT_THAT(eventKey, Eq(kKey)); - EXPECT_THAT(eventValue, Eq(kValue)); - store2->Unregister(&sink); -} - -TEST_F(AStore2, DoesNotGetValueWhenKeyDoesNotExist) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - string value; - uint32_t ttl; - EXPECT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, "none", value, ttl), - Eq(WPEFramework::Core::ERROR_UNKNOWN_KEY)); -} - -TEST_F(AStore2, DeletesKeyWhenKeyDoesNotExist) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(store2->DeleteKey( - IStore2::ScopeType::DEVICE, kAppId, "none"), - Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, DoesNotGetValueWhenDeletedKey) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(store2->DeleteKey( - IStore2::ScopeType::DEVICE, kAppId, kKey), - Eq(WPEFramework::Core::ERROR_NONE)); - string value; - uint32_t ttl; - EXPECT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_UNKNOWN_KEY)); -} - -TEST_F(AStore2, DoesNotGetValueWhenDeletedNamespace) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, kAppId), - Eq(WPEFramework::Core::ERROR_NONE)); - string value; - uint32_t ttl; - EXPECT_THAT(store2->GetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, value, ttl), - Eq(WPEFramework::Core::ERROR_NOT_EXIST)); -} - -TEST_F(AStore2, DoesNotSetValueWhenReachedMaxSize) -{ - store2 = WPEFramework::Core::ProxyType::Create( - kPath, kNewLimit, kMaxValue, kLimit); - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, kAppId), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, FlushesCache) -{ - EXPECT_THAT(store2->FlushCache(), Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, GetsKeysWhenNamespaceDoesNotExist) -{ - IStringIterator* it; - ASSERT_THAT(store2->GetKeys( - IStoreInspector::ScopeType::DEVICE, "none", it), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(it, NotNull()); - string element; - EXPECT_THAT(it->Next(element), IsFalse()); - it->Release(); -} - -TEST_F(AStore2, GetsKeys) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - IStringIterator* it; - ASSERT_THAT(store2->GetKeys( - IStoreInspector::ScopeType::DEVICE, kAppId, it), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(it, NotNull()); - string element; - ASSERT_THAT(it->Next(element), IsTrue()); - EXPECT_THAT(element, Eq(kKey)); - EXPECT_THAT(it->Next(element), IsFalse()); - it->Release(); -} - -TEST_F(AStore2, GetsNamespaces) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - IStringIterator* it; - ASSERT_THAT(store2->GetNamespaces( - IStoreInspector::ScopeType::DEVICE, it), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(it, NotNull()); - string element; - ASSERT_THAT(it->Next(element), IsTrue()); - EXPECT_THAT(element, Eq(kAppId)); - EXPECT_THAT(it->Next(element), IsFalse()); - it->Release(); -} - -TEST_F(AStore2, GetsStorageSizes) -{ - ASSERT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - IStoreInspector::INamespaceSizeIterator* it; - ASSERT_THAT(store2->GetStorageSizes( - IStoreInspector::ScopeType::DEVICE, it), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(it, NotNull()); - IStoreInspector::NamespaceSize element; - ASSERT_THAT(it->Next(element), IsTrue()); - EXPECT_THAT(element.ns, Eq(kAppId)); - EXPECT_THAT(element.size, Eq(strlen(kKey) + strlen(kValue))); - EXPECT_THAT(it->Next(element), IsFalse()); - it->Release(); -} - -TEST_F(AStore2, DoesNotGetNamespaceStorageLimitWhenNamespaceDoesNotExist) -{ - uint32_t value; - EXPECT_THAT(store2->GetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, "none", value), - Eq(WPEFramework::Core::ERROR_NOT_EXIST)); -} - -TEST_F(AStore2, DoesNotSetNamespaceStorageLimitWhenNamespaceEmpty) -{ - EXPECT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, "", kNewLimit), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetNamespaceStorageLimitWhenNamespaceTooLarge) -{ - EXPECT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, "this is too large", kNewLimit), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, SetsNamespaceStorageLimit) -{ - ASSERT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kNewLimit), - Eq(WPEFramework::Core::ERROR_NONE)); - uint32_t value; - ASSERT_THAT(store2->GetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, value), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(value, Eq(kNewLimit)); - // restore: - EXPECT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kLimit), - Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, DoesNotSetValueWhenReachedDefaultLimit) -{ - store2 = WPEFramework::Core::ProxyType::Create( - kPath, kMaxSize, kMaxValue, kMaxValue); - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, kAppId), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); -} - -TEST_F(AStore2, DoesNotSetValueWhenReachedLimit) -{ - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, kAppId), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kMaxValue), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, kValue, kNoTtl), - Eq(WPEFramework::Core::ERROR_INVALID_INPUT_LENGTH)); - // restore: - EXPECT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kLimit), - Eq(WPEFramework::Core::ERROR_NONE)); -} - -TEST_F(AStore2, SetsValueWhenDoesNotReachLimit) -{ - ASSERT_THAT(store2->DeleteNamespace(IStore2::ScopeType::DEVICE, kAppId), - Eq(WPEFramework::Core::ERROR_NONE)); - ASSERT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kMaxValue), - Eq(WPEFramework::Core::ERROR_NONE)); - EXPECT_THAT(store2->SetValue( - IStore2::ScopeType::DEVICE, kAppId, kKey, "", kNoTtl), - Eq(WPEFramework::Core::ERROR_NONE)); - // restore: - EXPECT_THAT(store2->SetNamespaceStorageLimit( - IStoreLimit::ScopeType::DEVICE, kAppId, kLimit), - Eq(WPEFramework::Core::ERROR_NONE)); -} diff --git a/PreinstallManager/CMakeLists.txt b/PreinstallManager/CMakeLists.txt deleted file mode 100644 index 9ac2ae0..0000000 --- a/PreinstallManager/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2025 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME PreinstallManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") - -set(PLUGIN_PREINSTALL_MANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_PREINSTALL_MANAGER_AUTOSTART false CACHE STRING "Automatically start start PreinstallManager plugin") -set(PLUGIN_PREINSTALL_MANAGER_EXTRA_LIBRARIES "") - -add_definitions(-DPREINSTALL_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DPREINSTALL_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DPREINSTALL_MANAGER_API_VERSION_NUMBER_PATCH=0) - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - PreinstallManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - - -set_source_files_properties(PreinstallManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - PreinstallManagerImplementation.cpp - Module.cpp) - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set(PREINSTALL_MANAGER_INCLUDES $ENV{PREINSTALL_MANAGER_INCLUDES}) -separate_arguments(PREINSTALL_MANAGER_INCLUDES) -include_directories(BEFORE ${PREINSTALL_MANAGER_INCLUDES}) -if (RDK_SERVICES_L1_TEST) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,mkdir -Wl,--wrap,access -Wl,--wrap,opendir -Wl,--wrap,readdir -Wl,--wrap,stat -Wl,--wrap,closedir) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,stat) -endif (RDK_SERVICES_L1_TEST) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_PREINSTALL_MANAGER_EXTRA_LIBRARIES}) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/PreinstallManager/Module.cpp b/PreinstallManager/Module.cpp deleted file mode 100644 index 42106eb..0000000 --- a/PreinstallManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PreinstallManager/Module.h b/PreinstallManager/Module.h deleted file mode 100644 index 24b6062..0000000 --- a/PreinstallManager/Module.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_PreinstallManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PreinstallManager/PreinstallManager.conf.in b/PreinstallManager/PreinstallManager.conf.in deleted file mode 100644 index 36d9faa..0000000 --- a/PreinstallManager/PreinstallManager.conf.in +++ /dev/null @@ -1,10 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.PreinstallManager" -autostart = "false" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_PREINSTALL_MANAGER_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) \ No newline at end of file diff --git a/PreinstallManager/PreinstallManager.config b/PreinstallManager/PreinstallManager.config deleted file mode 100644 index f84b251..0000000 --- a/PreinstallManager/PreinstallManager.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart ${PLUGIN_PREINSTALL_MANAGER_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.PreinstallManager") - -if(PLUGIN_PREINSTALL_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_PREINSTALL_MANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_PREINSTALL_MANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) \ No newline at end of file diff --git a/PreinstallManager/PreinstallManager.cpp b/PreinstallManager/PreinstallManager.cpp deleted file mode 100644 index 662f2ef..0000000 --- a/PreinstallManager/PreinstallManager.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "PreinstallManager.h" - -const string WPEFramework::Plugin::PreinstallManager::SERVICE_NAME = "org.rdk.PreinstallManager"; - -namespace WPEFramework -{ - - namespace - { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - PREINSTALL_MANAGER_API_VERSION_NUMBER_MAJOR, PREINSTALL_MANAGER_API_VERSION_NUMBER_MINOR, PREINSTALL_MANAGER_API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {}); - } - - namespace Plugin - { - - /* - *Register PreinstallManager module as wpeframework plugin - **/ - SERVICE_REGISTRATION(PreinstallManager, PREINSTALL_MANAGER_API_VERSION_NUMBER_MAJOR, PREINSTALL_MANAGER_API_VERSION_NUMBER_MINOR, PREINSTALL_MANAGER_API_VERSION_NUMBER_PATCH); - - PreinstallManager *PreinstallManager::_instance = nullptr; - - PreinstallManager::PreinstallManager() : mCurrentService(nullptr), - mConnectionId(0), - mPreinstallManagerImpl(nullptr), - mPreinstallManagerNotification(this), - mPreinstallManagerConfigure(nullptr) - { - SYSLOG(Logging::Startup, (_T("PreinstallManager Constructor"))); - if (nullptr == PreinstallManager::_instance) - { - PreinstallManager::_instance = this; - } - } - - PreinstallManager::~PreinstallManager() - { - SYSLOG(Logging::Shutdown, (string(_T("PreinstallManager Destructor")))); - PreinstallManager::_instance = nullptr; - } - - const string PreinstallManager::Initialize(PluginHost::IShell *service) - { - string message = ""; - - ASSERT(nullptr != service); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mPreinstallManagerImpl); - ASSERT(0 == mConnectionId); - - SYSLOG(Logging::Startup, (_T("PreinstallManager::Initialize: PID=%u"), getpid())); - - mCurrentService = service; - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - mCurrentService->Register(&mPreinstallManagerNotification); - - if (nullptr == (mPreinstallManagerImpl = mCurrentService->Root(mConnectionId, 5000, _T("PreinstallManagerImplementation")))) - { - SYSLOG(Logging::Startup, (_T("PreinstallManager::Initialize: object creation failed"))); - message = _T("PreinstallManager plugin could not be initialised"); - } - else if (nullptr == (mPreinstallManagerConfigure = mPreinstallManagerImpl->QueryInterface())) - { - SYSLOG(Logging::Startup, (_T("PreinstallManager::Initialize: did not provide a configuration interface"))); - message = _T("PreinstallManager implementation did not provide a configuration interface"); - } - else - { - // Register for notifications - mPreinstallManagerImpl->Register(&mPreinstallManagerNotification); - // Invoking Plugin API register to wpeframework - Exchange::JPreinstallManager::Register(*this, mPreinstallManagerImpl); - - if (Core::ERROR_NONE != mPreinstallManagerConfigure->Configure(mCurrentService)) - { - SYSLOG(Logging::Startup, (_T("PreinstallManager::Initialize: could not be configured"))); - message = _T("PreinstallManager could not be configured"); - } - } - } - else - { - SYSLOG(Logging::Startup, (_T("PreinstallManager::Initialize: service is not valid"))); - message = _T("PreinstallManager plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void PreinstallManager::Deinitialize(PluginHost::IShell *service) - { - ASSERT(mCurrentService == service); - - SYSLOG(Logging::Shutdown, (string(_T("PreinstallManager::Deinitialize")))); - - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - mCurrentService->Unregister(&mPreinstallManagerNotification); - - if (nullptr != mPreinstallManagerImpl) - { - mPreinstallManagerImpl->Unregister(&mPreinstallManagerNotification); - Exchange::JPreinstallManager::Unregister(*this); - - if (nullptr != mPreinstallManagerConfigure) - { - mPreinstallManagerConfigure->Release(); - mPreinstallManagerConfigure = nullptr; - } - - // Stop processing: - RPC::IRemoteConnection *connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mPreinstallManagerImpl->Release(); - - mPreinstallManagerImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mCurrentService->Release(); - mCurrentService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("PreinstallManager de-initialised")))); - } - - string PreinstallManager::Information() const - { - // No additional info to report - return (string()); - } - - void PreinstallManager::Deactivated(RPC::IRemoteConnection *connection) - { - if (connection->Id() == mConnectionId) - { - ASSERT(nullptr != mCurrentService); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mCurrentService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/PreinstallManager/PreinstallManager.h b/PreinstallManager/PreinstallManager.h deleted file mode 100644 index a6d820a..0000000 --- a/PreinstallManager/PreinstallManager.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -// #include -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework -{ - namespace Plugin - { - - class PreinstallManager : public PluginHost::IPlugin, public PluginHost::JSONRPC - { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IPreinstallManager::INotification - { - private: - Notification() = delete; - Notification(const Notification &) = delete; - Notification &operator=(const Notification &) = delete; - - public: - explicit Notification(PreinstallManager *parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IPreinstallManager::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection *) override - { - LOGINFO("PreinstallManager Notification Activated"); - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - LOGINFO("PreinstallManager Notification Deactivated"); - _parent.Deactivated(connection); - } - - void OnAppInstallationStatus(const string& jsonresponse) override - { - LOGINFO("PreinstallManager on OnAppInstallationStatus"); - Exchange::JPreinstallManager::Event::OnAppInstallationStatus(_parent, jsonresponse); - } - - private: - PreinstallManager &_parent; - }; - - public: - PreinstallManager(const PreinstallManager &) = delete; - PreinstallManager &operator=(const PreinstallManager &) = delete; - - PreinstallManager(); - virtual ~PreinstallManager(); - - BEGIN_INTERFACE_MAP(PreinstallManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IPreinstallManager, mPreinstallManagerImpl) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell *service) override; - void Deinitialize(PluginHost::IShell *service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection *connection); - - private: - PluginHost::IShell *mCurrentService{}; - uint32_t mConnectionId{}; - Exchange::IPreinstallManager *mPreinstallManagerImpl{}; - Core::Sink mPreinstallManagerNotification; - Exchange::IConfiguration* mPreinstallManagerConfigure; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static PreinstallManager *_instance; - }; - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/PreinstallManager/PreinstallManagerImplementation.cpp b/PreinstallManager/PreinstallManagerImplementation.cpp deleted file mode 100644 index 25d7b2c..0000000 --- a/PreinstallManager/PreinstallManagerImplementation.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "PreinstallManagerImplementation.h" - -#define AI_PREINSTALL_DIRECTORY "/opt/preinstall" //temporary directory for preinstall packages - -namespace WPEFramework -{ - namespace Plugin - { - - SERVICE_REGISTRATION(PreinstallManagerImplementation, 1, 0); - PreinstallManagerImplementation *PreinstallManagerImplementation::_instance = nullptr; - - PreinstallManagerImplementation::PreinstallManagerImplementation() - : mAdminLock(), mPreinstallManagerNotifications(), mCurrentservice(nullptr), - mPackageManagerInstallerObject(nullptr), mPackageManagerNotification(*this) - { - LOGINFO("Create PreinstallManagerImplementation Instance"); - if (nullptr == PreinstallManagerImplementation::_instance) - { - PreinstallManagerImplementation::_instance = this; - } - } - - PreinstallManagerImplementation *PreinstallManagerImplementation::getInstance() - { - return _instance; - } - - PreinstallManagerImplementation::~PreinstallManagerImplementation() - { - LOGINFO("Delete PreinstallManagerImplementation Instance"); - _instance = nullptr; - if (nullptr != mCurrentservice) - { - mCurrentservice->Release(); - mCurrentservice = nullptr; - } - if (nullptr != mPackageManagerInstallerObject) - { - releasePackageManagerObject(); - } - } - - /** - * Register a notification callback - */ - Core::hresult PreinstallManagerImplementation::Register(Exchange::IPreinstallManager::INotification *notification) - { - ASSERT(nullptr != notification); - - mAdminLock.Lock(); - - if (std::find(mPreinstallManagerNotifications.begin(), mPreinstallManagerNotifications.end(), notification) == mPreinstallManagerNotifications.end()) - { - LOGINFO("Register notification"); - mPreinstallManagerNotifications.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; - } - - /** - * Unregister a notification callback - */ - Core::hresult PreinstallManagerImplementation::Unregister(Exchange::IPreinstallManager::INotification *notification) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT(nullptr != notification); - - mAdminLock.Lock(); - - auto itr = std::find(mPreinstallManagerNotifications.begin(), mPreinstallManagerNotifications.end(), notification); - if (itr != mPreinstallManagerNotifications.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mPreinstallManagerNotifications.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; - } - - /** - * Initialize the implementation with the current service - */ - uint32_t PreinstallManagerImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_GENERAL; - if (service != nullptr) - { - mCurrentservice = service; - mCurrentservice->AddRef(); - result = Core::ERROR_NONE; - LOGINFO("PreinstallManagerImplementation service configured successfully"); - } - else - { - LOGERR("service is null \n"); - } - - return result; - } - - void PreinstallManagerImplementation::dispatchEvent(EventNames event, const JsonObject ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void PreinstallManagerImplementation::Dispatch(EventNames event, const JsonObject params) - { - switch (event) - { - case PREINSTALL_MANAGER_APP_INSTALLATION_STATUS: - { - if( params.HasLabel("jsonresponse") == false) - { - LOGERR("jsonresponse not found in params"); - break; - } - std::string jsonresponse = params["jsonresponse"].String(); - LOGINFO("Sending OnAppInstallationStatus event : %s", jsonresponse.c_str()); - mAdminLock.Lock(); - for (auto notification : mPreinstallManagerNotifications) - { - notification->OnAppInstallationStatus(jsonresponse); - LOGTRACE(); - } - mAdminLock.Unlock(); - break; - } - default: - LOGERR("Unknown event: %d", static_cast(event)); - break; - } - } - - /** - * Pass on the AppInstallationStatus event from package manager to all registered listeners - */ - void PreinstallManagerImplementation::handleOnAppInstallationStatus(const std::string &jsonresponse) - { - if (!jsonresponse.empty()) - { - JsonObject eventDetails; - eventDetails["jsonresponse"] = jsonresponse; - dispatchEvent(PREINSTALL_MANAGER_APP_INSTALLATION_STATUS, eventDetails); - } - else - { - LOGERR("jsonresponse string from package manager is empty"); - } - } - - Core::hresult PreinstallManagerImplementation::createPackageManagerObject() - { - Core::hresult status = Core::ERROR_GENERAL; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null \n"); - } - else if (nullptr == (mPackageManagerInstallerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.PackageManagerRDKEMS"))) - { - LOGERR("mPackageManagerInstallerObject is null \n"); - } - else - { - LOGINFO("created PackageInstaller Object\n"); - mPackageManagerInstallerObject->AddRef(); - mPackageManagerInstallerObject->Register(&mPackageManagerNotification); - status = Core::ERROR_NONE; - } - return status; - } - - void PreinstallManagerImplementation::releasePackageManagerObject() - { - ASSERT(nullptr != mPackageManagerInstallerObject); - if (mPackageManagerInstallerObject) - { - mPackageManagerInstallerObject->Unregister(&mPackageManagerNotification); - mPackageManagerInstallerObject->Release(); - mPackageManagerInstallerObject = nullptr; - } - } - - //compare package versions - bool PreinstallManagerImplementation::isNewerVersion(const std::string &v1, const std::string &v2) - { - // Strip at first '-' or '+' - std::string::size_type pos1 = std::min(v1.find('-'), v1.find('+')); - std::string::size_type pos2 = std::min(v2.find('-'), v2.find('+')); - - std::string base1 = (pos1 == std::string::npos) ? v1 : v1.substr(0, pos1); - std::string base2 = (pos2 == std::string::npos) ? v2 : v2.substr(0, pos2); - - int maj1 = 0, min1 = 0, patch1 = 0, build1 = 0; - int maj2 = 0, min2 = 0, patch2 = 0, build2 = 0; - - if (std::sscanf(base1.c_str(), "%d.%d.%d.%d", &maj1, &min1, &patch1, &build1) < 3) - { - LOGERR("Version string '%s' is not in valid format", v1.c_str()); - return false; - } - if (std::sscanf(base2.c_str(), "%d.%d.%d.%d", &maj2, &min2, &patch2, &build2) < 3) - { - LOGERR("Version string '%s' is not in valid format", v2.c_str()); - return false; - } - - if (maj1 != maj2) - return maj1 > maj2; - if (min1 != min2) - return min1 > min2; - if (patch1 != patch2) - return patch1 > patch2; - if (build1 != build2) - return build1 > build2; - - return false; // equal - } - - // bool packageWgtExists(const std::string& folderPath) //required?? - // { - // std::string packageWgtPath = folderPath + "/package.wgt"; - // struct stat st; - // return (stat(packageWgtPath.c_str(), &st) == 0) && S_ISREG(st.st_mode); - // } - - /** - * Traverse the preinstall directory and populate the list of packages to be preinstalled, - * also fetches the package details - */ - bool PreinstallManagerImplementation::readPreinstallDirectory(std::list &packages) - { - ASSERT(nullptr != mPackageManagerInstallerObject); - std::string preinstallDir = AI_PREINSTALL_DIRECTORY; - DIR *dir = opendir(preinstallDir.c_str()); - if (!dir) - { - LOGINFO("Failed to open directory: %s", preinstallDir.c_str()); - return false; - } - - struct dirent *entry; - while ((entry = readdir(dir)) != NULL) - { - std::string filename(entry->d_name); - - // Skip "." and ".." - if (filename == "." || filename == "..") - continue; - - std::string filepath = preinstallDir + "/" + filename; - - PackageInfo packageInfo; - packageInfo.fileLocator = filepath + "/package.wgt"; - LOGDBG("Found package folder: %s", filepath.c_str()); - if (mPackageManagerInstallerObject->GetConfigForPackage(packageInfo.fileLocator, packageInfo.packageId, packageInfo.version, packageInfo.configMetadata) == Core::ERROR_NONE) - { - LOGINFO("Found package: %s, version: %s", packageInfo.packageId.c_str(), packageInfo.version.c_str()); - } - else - { - LOGINFO("Skipping invalid package file: %s", filename.c_str()); - packageInfo.installStatus = "SKIPPED: getConfig failed for [" + filename + "]"; - // continue; -> so that it is printed as skipped and not go undetected - } - packages.push_back(packageInfo); - } - - closedir(dir); - return true; - } - - string PreinstallManagerImplementation::getFailReason(FailReason reason) { - switch (reason) { - case FailReason::SIGNATURE_VERIFICATION_FAILURE : return "SIGNATURE_VERIFICATION_FAILURE"; - case FailReason::PACKAGE_MISMATCH_FAILURE : return "PACKAGE_MISMATCH_FAILURE"; - case FailReason::INVALID_METADATA_FAILURE : return "INVALID_METADATA_FAILURE"; - case FailReason::PERSISTENCE_FAILURE : return "PERSISTENCE_FAILURE"; - default: return "NONE"; - } - } - - /* - * @brief Checks the preinstall directory for packages to be preinstalled and installs them as needed. - * @Params[in] : bool forceInstall - * @Params[out] : None - * @return : Core::hresult - */ - Core::hresult PreinstallManagerImplementation::StartPreinstall(bool forceInstall) - { - Core::hresult result = Core::ERROR_GENERAL; - auto installStart = std::chrono::steady_clock::now(); // for measuring duration taken - - if (nullptr == mPackageManagerInstallerObject) - { - LOGINFO("Create PackageManager Remote store object"); - if (Core::ERROR_NONE != createPackageManagerObject()) - { - LOGERR("Failed to create PackageManagerObject"); - return result; - } - } - ASSERT(nullptr != mPackageManagerInstallerObject); - - // read the preinstall directory and populate packages - std::list preinstallPackages; // all apps in preinstall directory - if (!readPreinstallDirectory(preinstallPackages)) - { - LOGERR("Failed to read preinstall directory"); - return result; - } - - if (!forceInstall) // if false, we need to check installed packages - { - LOGWARN("forceInstall is disabled"); - Exchange::IPackageInstaller::IPackageIterator *packageList = nullptr; - - // fetch installed packages - if (mPackageManagerInstallerObject->ListPackages(packageList) != Core::ERROR_NONE && packageList != nullptr) - { - LOGERR("ListPackage is returning Error or Packages is nullptr"); - return result; - } - - WPEFramework::Exchange::IPackageInstaller::Package package; - std::unordered_map existingApps; // packageId -> version - - while (packageList->Next(package) && package.state == InstallState::INSTALLED) // only consider installed apps - { - existingApps[package.packageId] = package.version; - // todo check for installState if needed - // multiple apps possible with same packageId but different version - } - - // filter to-be-installed apps - for (auto toBeInstalledApp = preinstallPackages.begin(); toBeInstalledApp != preinstallPackages.end(); /* skip */) - { - bool remove = false; - - // check if app is already installed - auto it = existingApps.find(toBeInstalledApp->packageId); - if (it != existingApps.end()) - { - const std::string &installedVersion = it->second; - - // check if to-be-installed version is newer - if (!isNewerVersion(toBeInstalledApp->version, installedVersion)) - { - // not newer (equal or older) → skip install - LOGINFO("Not installing package: %s, version: %s (installed version: %s)", - toBeInstalledApp->packageId.c_str(), - toBeInstalledApp->version.c_str(), - installedVersion.c_str()); - remove = true; - } - else - { - LOGINFO("Installing newer version of package: %s, version: %s (installed version: %s)", - toBeInstalledApp->packageId.c_str(), - toBeInstalledApp->version.c_str(), - installedVersion.c_str()); - } - // todo uninstall older version if needed - } - - if (remove) - { - toBeInstalledApp = preinstallPackages.erase(toBeInstalledApp); // advances automatically - } - else - { - ++toBeInstalledApp; - } - } - - } - // install the apps - bool installError = false; - int failedApps = 0; - int totalApps = preinstallPackages.size(); - // std::list failedAppsList; - - for (auto &pkg : preinstallPackages) - { - if((pkg.packageId.empty() || pkg.version.empty() || pkg.fileLocator.empty()) /*&& !forceInstall */) // force install anyway - { - LOGERR("Skipping invalid package with empty fields: %s", pkg.fileLocator.empty() ? "NULL" : pkg.fileLocator.c_str()); - if(pkg.installStatus.empty()) // do not overwrite if already set to skipped - { - pkg.installStatus = "FAILED: empty fields"; - } - //populate empty fields to avoid null errors - pkg.fileLocator = pkg.fileLocator.empty() ? "NULL" : pkg.fileLocator; - pkg.packageId = pkg.packageId.empty() ? pkg.fileLocator : pkg.packageId; // use fileLocator if packageId is empty for logging - pkg.version = pkg.version.empty() ? "NULL" : pkg.version; - // installError = true; //required?? - failedApps++; - continue; // do not install with empty fields - } - - LOGINFO("Installing package: %s, version: %s", pkg.packageId.c_str(), pkg.version.c_str()); - - FailReason failReason; - Exchange::IPackageInstaller::IKeyValueIterator* additionalMetadata = nullptr; // todo add additionalMetadata if needed - // additionalMetadata = Core::Service>::Create(keyValues); - - - Core::hresult installResult = mPackageManagerInstallerObject->Install(pkg.packageId, pkg.version, additionalMetadata, pkg.fileLocator, failReason); - if (installResult != Core::ERROR_NONE) - { - LOGERR("Failed to install package: %s, version: %s, failReason: %s", pkg.packageId.c_str(), pkg.version.c_str(), getFailReason(failReason).c_str()); - installError = true; - failedApps++; - // failedAppsList.push_back(pkg.packageId + "_" + pkg.version); - pkg.installStatus = "FAILED: reason " + getFailReason(failReason); - continue; - } - else - { - LOGINFO("Successfully installed package: %s, version: %s, fileLocator: %s", pkg.packageId.c_str(), pkg.version.c_str(), pkg.fileLocator.c_str()); - pkg.installStatus = "SUCCESS"; - } - } - auto installEnd = std::chrono::steady_clock::now(); - auto installDuration = std::chrono::duration_cast(installEnd - installStart).count(); - auto installDurationMs = std::chrono::duration_cast(installEnd - installStart).count(); - LOGDBG("Process completed in %lld seconds (%lld ms)", installDuration, installDurationMs); - LOGINFO("Installation summary: %d/%d packages installed successfully. %d apps failed.", totalApps - failedApps, totalApps, failedApps); - // print package wise result - for (const auto &pkg : preinstallPackages) - { - LOGINFO("Package: %s [version:%s]............status:[ %s ]", pkg.packageId.c_str(), pkg.version.c_str(), pkg.installStatus.c_str()); - } - - //cleanup - releasePackageManagerObject(); - - if(!installError) - { - result = Core::ERROR_NONE; // return error if any app install fails todo required?? - } - - return result; - } - - } /* namespace Plugin */ -} /* namespace WPEFramework */ \ No newline at end of file diff --git a/PreinstallManager/PreinstallManagerImplementation.h b/PreinstallManager/PreinstallManagerImplementation.h deleted file mode 100644 index a4949c5..0000000 --- a/PreinstallManager/PreinstallManagerImplementation.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "tracing/Logging.h" -#include "UtilsLogging.h" -#include -#include -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - // typedef Exchange::IPreinstallManager::PreinstallState PreinstallState; - // typedef Exchange::IPreinstallManager::PreinstallFailReason PreinstallFailReason; - // typedef Exchange::IPreinstallManager::AppInstallInfo AppInstallInfo; - - class PreinstallManagerImplementation : public Exchange::IPreinstallManager, public Exchange::IConfiguration - { - - public: - PreinstallManagerImplementation(); - ~PreinstallManagerImplementation() override; - - static PreinstallManagerImplementation *getInstance(); - PreinstallManagerImplementation(const PreinstallManagerImplementation &) = delete; - PreinstallManagerImplementation &operator=(const PreinstallManagerImplementation &) = delete; - - BEGIN_INTERFACE_MAP(PreinstallManagerImplementation) - INTERFACE_ENTRY(Exchange::IPreinstallManager) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - public: - typedef struct _PackageInfo - { - string fileLocator; - string packageId; - string version; - WPEFramework::Exchange::RuntimeConfig configMetadata; - string installStatus; // optional field to store install status for logging purpose - } PackageInfo; - - enum EventNames { - PREINSTALL_MANAGER_UNKNOWN = 0, - PREINSTALL_MANAGER_APP_INSTALLATION_STATUS - }; - - typedef Exchange::IPackageInstaller::InstallState InstallState; - typedef Exchange::IPackageInstaller::FailReason FailReason; - - private: - class PackageManagerNotification : public Exchange::IPackageInstaller::INotification { - - public: - PackageManagerNotification(PreinstallManagerImplementation& parent) : mParent(parent){} - ~PackageManagerNotification(){} - - void OnAppInstallationStatus(const string& jsonresponse) - { - // LOGINFO("Received Installation Status event from PackageManager"); - mParent.handleOnAppInstallationStatus(jsonresponse); - } - - BEGIN_INTERFACE_MAP(PackageManagerNotification) - INTERFACE_ENTRY(Exchange::IPackageInstaller::INotification) - END_INTERFACE_MAP - - private: - PreinstallManagerImplementation& mParent; - }; - - private: - class EXTERNAL Job : public Core::IDispatch - { - protected: - Job(PreinstallManagerImplementation *preinstallManagerImplementation, EventNames event, JsonObject ¶ms) - : mPreinstallManagerImplementation(preinstallManagerImplementation), _event(event), _params(params) - { - if (mPreinstallManagerImplementation != nullptr) - { - mPreinstallManagerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job &) = delete; - Job &operator=(const Job &) = delete; - ~Job() - { - if (mPreinstallManagerImplementation != nullptr) - { - mPreinstallManagerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(PreinstallManagerImplementation *preinstallManagerImplementation, EventNames event, JsonObject params) - { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(preinstallManagerImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(preinstallManagerImplementation, event, params))); -#endif - } - - virtual void Dispatch() - { - mPreinstallManagerImplementation->Dispatch(_event, _params); - } - - private: - PreinstallManagerImplementation *mPreinstallManagerImplementation; - const EventNames _event; - const JsonObject _params; - }; - - public: - Core::hresult Register(Exchange::IPreinstallManager::INotification *notification) override; - Core::hresult Unregister(Exchange::IPreinstallManager::INotification *notification) override; - Core::hresult StartPreinstall(bool forceInstall) override; - void handleOnAppInstallationStatus(const std::string &jsonresponse); - - // // IConfiguration methods - uint32_t Configure(PluginHost::IShell *service) override; - - private: /* private methods */ - Core::hresult createPackageManagerObject(); - void releasePackageManagerObject(); - bool isValidSemVer(const std::string &version); - bool isNewerVersion(const std::string &v1, const std::string &v2); - bool readPreinstallDirectory(std::list &packages); - string getFailReason(FailReason reason); - - private: - mutable Core::CriticalSection mAdminLock; - std::list mPreinstallManagerNotifications; - PluginHost::IShell *mCurrentservice; - Exchange::IPackageInstaller* mPackageManagerInstallerObject; - Core::Sink mPackageManagerNotification; - void dispatchEvent(EventNames, const JsonObject ¶ms); - void Dispatch(EventNames event, const JsonObject params); - friend class Job; - - public /*members*/: - static PreinstallManagerImplementation *_instance; - - public: /* public methods */ - // void updateCurrentAction(const std::string &appId, CurrentAction action); - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/PreinstallManager/PreinstallManagerPlugin.json b/PreinstallManager/PreinstallManagerPlugin.json deleted file mode 100644 index 6857e5c..0000000 --- a/PreinstallManager/PreinstallManagerPlugin.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "plugin.schema.json", - "info": { - "title": "PreinstallManager Plugin", - "callsign": "PreinstallManager", - "locator": "libThunderPreinstallManager.so", - "status": "development", - "description": [ - "" - ], - "version": "1.0" - }, - "interface": { - "$cppref": "{cppinterfacedir}/IPreinstallManager.h" - } -} \ No newline at end of file diff --git a/RDKShell/CHANGELOG.md b/RDKShell/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/RDKShell/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/RDKShell/CMakeLists.txt b/RDKShell/CMakeLists.txt deleted file mode 100755 index a8b6844..0000000 --- a/RDKShell/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME RDKShell) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_RDKSHELL_AUTOSTART true CACHE STRING "Automatically start RDKShell plugin") -set(PLUGIN_RDKSHELL_EXTRA_LIBRARIES "") -set(PLUGIN_RDKSHELL_STARTUPORDER "" CACHE STRING "Automatically start RDKShell plugin") - -option(PLUGIN_RDKSHELL_READ_MAC_ON_STARTUP "PLUGIN_RDKSHELL_READ_MAC_ON_STARTUP" OFF) -option(PLUGIN_HIBERNATESUPPORT "Include hibernate support in the build." OFF) -option(PLUGIN_HIBERNATE_NATIVE_APPS_ON_SUSPENDED "Try to hibernate native apps on suspended." OFF) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(IARMBus) - -set (RDKSHELL_SOURCES) -list(APPEND RDKSHELL_SOURCES RDKShell.cpp) -list(APPEND RDKSHELL_SOURCES Module.cpp) - -if (RIALTO_FEATURE) - add_definitions("-DENABLE_RIALTO_FEATURE") - list(APPEND RDKSHELL_SOURCES RialtoConnector.cpp) -endif(RIALTO_FEATURE) - -add_library(${MODULE_NAME} SHARED ${RDKSHELL_SOURCES}) -if(RIALTO_FEATURE) - target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins libRialtoServerManager.so) -endif(RIALTO_FEATURE) -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -if (PLUGIN_RDKSHELL_READ_MAC_ON_STARTUP) - add_definitions("-DRDKSHELL_READ_MAC_ON_STARTUP") - set(PLUGIN_RDKSHELL_EXTRA_LIBRARIES "-lFactory-hal") -endif (PLUGIN_RDKSHELL_READ_MAC_ON_STARTUP) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - -if(PLUGIN_HIBERNATESUPPORT) - target_compile_definitions(${MODULE_NAME} PRIVATE HIBERNATE_SUPPORT_ENABLED=1) -endif() - -if(PLUGIN_HIBERNATE_NATIVE_APPS_ON_SUSPENDED) - target_compile_definitions(${MODULE_NAME} PRIVATE HIBERNATE_NATIVE_APPS_ON_SUSPENDED=1) -endif() - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers ${IARMBUS_INCLUDE_DIRS} ) - -set_source_files_properties(RDKShell.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -set(RDKSHELL_INCLUDES $ENV{RDKSHELL_INCLUDES}) -separate_arguments(RDKSHELL_INCLUDES) -include_directories(BEFORE ${RDKSHELL_INCLUDES}) -if (NOT RDK_SERVICES_L1_TEST) - target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins -lrdkshell ${PLUGIN_RDKSHELL_EXTRA_LIBRARIES}) -else(RDK_SERVICES_L1_TEST) - target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_RDKSHELL_EXTRA_LIBRARIES}) -endif(RDK_SERVICES_L1_TEST) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/RDKShell/Module.cpp b/RDKShell/Module.cpp deleted file mode 100755 index 69ecca0..0000000 --- a/RDKShell/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/RDKShell/Module.h b/RDKShell/Module.h deleted file mode 100755 index e9a8000..0000000 --- a/RDKShell/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_RDKShell -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/RDKShell/RDKShell.conf.in b/RDKShell/RDKShell.conf.in deleted file mode 100644 index 62860b6..0000000 --- a/RDKShell/RDKShell.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.RDKShell" -autostart = "@PLUGIN_RDKSHELL_AUTOSTART@" -startuporder = "@PLUGIN_RDKSHELL_STARTUPORDER@" diff --git a/RDKShell/RDKShell.config b/RDKShell/RDKShell.config deleted file mode 100755 index 6d8b588..0000000 --- a/RDKShell/RDKShell.config +++ /dev/null @@ -1,7 +0,0 @@ -set (autostart ${PLUGIN_RDKSHELL_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.RDKShell") - -if(PLUGIN_RDKSHELL_STARTUPORDER) -set (startuporder ${PLUGIN_RDKSHELL_STARTUPORDER}) -endif() diff --git a/RDKShell/RDKShell.cpp b/RDKShell/RDKShell.cpp deleted file mode 100755 index 9f133f8..0000000 --- a/RDKShell/RDKShell.cpp +++ /dev/null @@ -1,7970 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "RDKShell.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "UtilsJsonRpc.h" -#include "UtilsLOG_MILESTONE.h" -#include "UtilsUnused.h" -#include "UtilsgetRFCConfig.h" -#include "UtilsString.h" - -#ifdef RDKSHELL_READ_MAC_ON_STARTUP -#include "FactoryProtectHal.h" -#endif //RDKSHELL_READ_MAC_ON_STARTUP - - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 4 -#define API_VERSION_NUMBER_PATCH 6 - -const string WPEFramework::Plugin::RDKShell::SERVICE_NAME = "org.rdk.RDKShell"; -//methods -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_MOVE_TO_FRONT = "moveToFront"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_MOVE_TO_BACK = "moveToBack"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_MOVE_BEHIND = "moveBehind"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_FOCUS = "setFocus"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_FOCUSED = "getFocused"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_KILL = "kill"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_KEY_INTERCEPT = "addKeyIntercept"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_KEY_INTERCEPTS = "addKeyIntercepts"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_REMOVE_KEY_INTERCEPT = "removeKeyIntercept"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_KEY_LISTENER = "addKeyListener"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_REMOVE_KEY_LISTENER = "removeKeyListener"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_KEY_METADATA_LISTENER = "addKeyMetadataListener"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_REMOVE_KEY_METADATA_LISTENER = "removeKeyMetadataListener"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_INJECT_KEY = "injectKey"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GENERATE_KEYS = "generateKey"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_SCREEN_RESOLUTION = "getScreenResolution"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_SCREEN_RESOLUTION = "setScreenResolution"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_CREATE_DISPLAY = "createDisplay"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_CLIENTS = "getClients"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_Z_ORDER = "getZOrder"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_BOUNDS = "getBounds"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_BOUNDS = "setBounds"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_VISIBILITY = "getVisibility"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_VISIBILITY = "setVisibility"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_OPACITY = "getOpacity"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_OPACITY = "setOpacity"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_SCALE = "getScale"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_SCALE = "setScale"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_HOLE_PUNCH = "getHolePunch"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_HOLE_PUNCH = "setHolePunch"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_LOG_LEVEL = "getLogLevel"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_LOG_LEVEL = "setLogLevel"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SHOW_SPLASH_LOGO = "showSplashLogo"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_HIDE_SPLASH_LOGO = "hideSplashLogo"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_REMOVE_ANIMATION = "removeAnimation"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_ANIMATION = "addAnimation"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_INACTIVITY_REPORTING = "enableInactivityReporting"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_INACTIVITY_INTERVAL = "setInactivityInterval"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_RESET_INACTIVITY_TIME = "resetInactivityTime"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SCALE_TO_FIT = "scaleToFit"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_LAUNCH = "launch"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_LAUNCH_APP = "launchApplication"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SUSPEND = "suspend"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SUSPEND_APP = "suspendApplication"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_RESUME_APP = "resumeApplication"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_DESTROY = "destroy"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_AVAILABLE_TYPES = "getAvailableTypes"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_STATE = "getState"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_SYSTEM_MEMORY = "getSystemMemory"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_SYSTEM_RESOURCE_INFO = "getSystemResourceInfo"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_MEMORY_MONITOR = "setMemoryMonitor"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SHOW_WATERMARK = "showWatermark"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SHOW_FULL_SCREEN_IMAGE = "showFullScreenImage"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_HIDE_FULL_SCREEN_IMAGE = "hideFullScreenImage"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_LAUNCH_FACTORY_APP = "launchFactoryApp"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_LAUNCH_FACTORY_APP_SHORTCUT = "launchFactoryAppShortcut"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_LAUNCH_RESIDENT_APP = "launchResidentApp"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_TOGGLE_FACTORY_APP = "toggleFactoryApp"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_EXIT_AGING_MODE = "exitAgingMode"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_KEYREPEATS = "enableKeyRepeats"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_KEYREPEATS_ENABLED = "getKeyRepeatsEnabled"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_TOPMOST = "setTopmost"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_VIRTUAL_RESOLUTION = "getVirtualResolution"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_VIRTUAL_RESOLUTION = "setVirtualResolution"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_VIRTUAL_DISPLAY = "enableVirtualDisplay"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_VIRTUAL_DISPLAY_ENABLED = "getVirtualDisplayEnabled"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_LAST_WAKEUP_KEY = "getLastWakeupKey"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_HIDE_ALL_CLIENTS = "hideAllClients"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_IGNORE_KEY_INPUTS = "ignoreKeyInputs"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_SCREENSHOT = "getScreenshot"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_EASTER_EGGS = "enableEasterEggs"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_LOGS_FLUSHING = "enableLogsFlushing"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_LOGS_FLUSHING_ENABLED = "getLogsFlushingEnabled"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ADD_EASTER_EGGS = "addEasterEggs"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_REMOVE_EASTER_EGGS = "removeEasterEggs"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_EASTER_EGGS = "getEasterEggs"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SHOW_CURSOR = "showCursor"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_HIDE_CURSOR = "hideCursor"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_CURSOR_SIZE = "getCursorSize"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_CURSOR_SIZE = "setCursorSize"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_ENABLE_INPUT_EVENTS = "enableInputEvents"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_AV_BLOCKED = "setAVBlocked"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_AV_BLOCKED_APPS = "getBlockedAVApplications"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_KEY_REPEAT_CONFIG = "keyRepeatConfig"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_GET_GRAPHICS_FRAME_RATE = "getGraphicsFrameRate"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_SET_GRAPHICS_FRAME_RATE = "setGraphicsFrameRate"; -#ifdef HIBERNATE_SUPPORT_ENABLED -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_HIBERNATE = "hibernate"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_METHOD_RESTORE = "restore"; -#endif - -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_USER_INACTIVITY = "onUserInactivity"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_LAUNCHED = "onApplicationLaunched"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_CONNECTED = "onApplicationConnected"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_DISCONNECTED = "onApplicationDisconnected"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_TERMINATED = "onApplicationTerminated"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_FIRST_FRAME = "onApplicationFirstFrame"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_SUSPENDED = "onApplicationSuspended"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_RESUMED = "onApplicationResumed"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_ACTIVATED = "onApplicationActivated"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_APP_FOCUSCHANGED = "onApplicationFocusChanged"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_LAUNCHED = "onLaunched"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_SUSPENDED = "onSuspended"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_DESTROYED = "onDestroyed"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_PLUGIN_SUSPENDED = "onPluginSuspended"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING = "onDeviceLowRamWarning"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING = "onDeviceCriticallyLowRamWarning"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING_CLEARED = "onDeviceLowRamWarningCleared"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING_CLEARED = "onDeviceCriticallyLowRamWarningCleared"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_EASTER_EGG = "onEasterEgg"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_WILL_DESTROY = "onWillDestroy"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_SCREENSHOT_COMPLETE = "onScreenshotComplete"; -#ifdef HIBERNATE_SUPPORT_ENABLED -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_HIBERNATED = "onHibernated"; -const string WPEFramework::Plugin::RDKShell::RDKSHELL_EVENT_ON_RESTORED = "onRestored"; -#endif - -using namespace std; -using namespace RdkShell; -using namespace Utils; -extern int gCurrentFramerate; -bool receivedResolutionRequest = false; -bool receivedFullScreenImageRequest= false; -std::string fullScreenImagePath; -bool receivedShowWatermarkRequest = false; -bool receivedShowSplashScreenRequest = false; -unsigned int gSplashScreenDisplayTime = 0; -unsigned int resolutionWidth = 1280; -unsigned int resolutionHeight = 720; -bool gRdkShellSurfaceModeEnabled = false; -static std::string sThunderSecurityToken; -std::shared_ptr> gSystemServiceConnection; -bool gSystemServiceEventsSubscribed = false; -static bool sResidentAppFirstActivated = false; -bool sPersistentStoreWaitProcessed = false; -bool sPersistentStoreFirstActivated = false; -bool sPersistentStorePreLaunchChecked=false; -bool sFactoryModeStart = false; -bool sFactoryModeBlockResidentApp = false; -bool sForceResidentAppLaunch = false; -static bool sRunning = true; -bool needsScreenshot = false; -sem_t gInitializeSemaphore; - -#ifdef HIBERNATE_SUPPORT_ENABLED -std::mutex gSuspendedOrHibernatedApplicationsMutex; -map gSuspendedOrHibernatedApplications; - -std::mutex gHibernateBlockedMutex; -int gHibernateBlocked; -std::condition_variable gHibernateBlockedCondVariable; -#endif - -#ifdef HIBERNATE_NATIVE_APPS_ON_SUSPENDED -std::set gLaunchedToSuspended; -std::mutex gLaunchedToSuspendedMutex; -#endif - -#define ANY_KEY 65536 -#define RDKSHELL_THUNDER_TIMEOUT 20000 -#define RDKSHELL_POWER_TIME_WAIT 2.5 -#define THUNDER_ACCESS_DEFAULT_VALUE "127.0.0.1:9998" -#define RDKSHELL_WILLDESTROY_EVENT_WAITTIME 1 -#define RDKSHELL_TRY_LOCK_WAIT_TIME_IN_MS 250 - -static std::string gThunderAccessValue = THUNDER_ACCESS_DEFAULT_VALUE; -static uint32_t gWillDestroyEventWaitTime = RDKSHELL_WILLDESTROY_EVENT_WAITTIME; -#define SYSTEM_SERVICE_CALLSIGN "org.rdk.System" -#define RESIDENTAPP_CALLSIGN "ResidentApp" -#define PERSISTENT_STORE_CALLSIGN "org.rdk.PersistentStore" -#define LISA_CALLSIGN "LISA" - -#define RECONNECTION_TIME_IN_MILLISECONDS 5000 - -#define REMOTECONTROL_CALLSIGN "org.rdk.RemoteControl.1" -#define KEYCODE_INVALID -1 -#define RETRY_INTERVAL_250MS 250000 - -#define RDKSHELL_SURFACECLIENT_DISPLAYNAME "rdkshell_display" -enum FactoryAppLaunchStatus -{ - NOTLAUNCHED = 0, - STARTED, - COMPLETED -}; - -enum RDKShellLaunchType -{ - UNKNOWN = 0, - CREATE, - ACTIVATE, - SUSPEND, - RESUME -}; - -enum AppLastExitReason -{ - UNDEFINED = 0, - CRASH, - DEACTIVATED -}; - -FactoryAppLaunchStatus sFactoryAppLaunchStatus = NOTLAUNCHED; - -#ifdef HIBERNATE_SUPPORT_ENABLED - -static void setHibernateBlocked(bool val) -{ - std::unique_lock lock(gHibernateBlockedMutex); - if (val) - { - gHibernateBlocked++; - } - else - { - gHibernateBlocked--; - } - std::cout << "setHibernateBlocked("<< gHibernateBlocked <<")" << std::endl; - lock.unlock(); - gHibernateBlockedCondVariable.notify_all(); -} - -static bool waitForHibernateUnblocked(int timeoutMs) -{ - std::unique_lock lock(gHibernateBlockedMutex); - while (gHibernateBlocked > 0) - { - std::cout << "Hibernation blocked, waiting" << std::endl; - if (gHibernateBlockedCondVariable.wait_for(lock, std::chrono::milliseconds(timeoutMs)) - == std::cv_status::timeout) - break; - } - - if (gHibernateBlocked > 0) - { - std::cout << "Hibernation still blocked after " << timeoutMs << "ms !" << std::endl; - return false; - } - - std::cout << "Hibernation not blocked" << std::endl; - return true; -} - -#endif - -namespace WPEFramework { - namespace Plugin { - - void RDKShell::TaskQueue::push(RDKShell::TaskQueue::Task task) - { - std::lock_guard lg(mMutex); - mQueue.push(task); - } - - bool RDKShell::TaskQueue::pop(RDKShell::TaskQueue::Task& outTask) - { - std::lock_guard lg(mMutex); - if(mQueue.empty()) { - return false; - } - outTask = mQueue.front(); - mQueue.pop(); - return true; - } - - namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {subsystem::GRAPHICS} - ); - } - - namespace { - // rdk Shell should use inter faces -#ifndef USE_THUNDER_R4 - class Job : public Core::IDispatchType { -#else - class Job : public Core::IDispatch { -#endif /* USE_THUNDER_R4 */ - public: - Job(std::function work) - : _work(work) - { - } - void Dispatch() override - { - _work(); - } - - private: - std::function _work; - }; - uint32_t cloneService(PluginHost::IShell* shell, const string& basecallsign, const string& newcallsign) - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - Core::Event event(false, true); -#ifndef USE_THUNDER_R4 - Core::IWorkerPool::Instance().Submit(Core::ProxyType>(Core::ProxyType::Create([&]() { -#else - Core::IWorkerPool::Instance().Submit(Core::ProxyType(Core::ProxyType::Create([&]() { -#endif /* USE_THUNDER_R4 */ - auto interface = shell->QueryInterfaceByCallsign(""); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IController" << std::endl; - } else { - result = interface->Clone(basecallsign, newcallsign); - std::cout << "IController clone status " << result << std::endl; - interface->Release(); - } - event.SetEvent(); - }))); - event.Lock(); - return result; - } - uint32_t getValue(PluginHost::IShell* shell, const string& ns, const string& key, string& value) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(PERSISTENT_STORE_CALLSIGN); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IStore" << std::endl; - } else { - result = interface->GetValue(ns, key, value); - std::cout << "IStore status " << result << " for get " << key << std::endl; - interface->Release(); - } - return result; - } - uint32_t setValue(PluginHost::IShell* shell, const string& ns, const string& key, const string& value) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(PERSISTENT_STORE_CALLSIGN); - auto storeInterface = shell->QueryInterfaceByCallsign(PERSISTENT_STORE_CALLSIGN); - if (interface == nullptr || storeInterface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IStore" << std::endl; - } else { - result = interface->SetValue(ns, key, value); - std::cout << "IStore status " << result << " for set " << key << std::endl; - result = storeInterface->FlushCache(); - std::cout << "flushCache status " << result << std::endl; - interface->Release(); - storeInterface->Release(); - } - return result; - } - uint32_t getConfig(PluginHost::IShell* shell, const string& callsign, string& config) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = Core::ERROR_NONE; - config = interface->ConfigLine(); - std::cout << "IShell config " << config << " for " << callsign << std::endl; - interface->Release(); - } - return result; - } - uint32_t setConfig(PluginHost::IShell* shell, const string& callsign, const string& config) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = interface->ConfigLine(config); - std::cout << "IShell config status " << result << " for " << callsign << std::endl; - interface->Release(); - } - return result; - } - uint32_t getServiceState(PluginHost::IShell* shell, const string& callsign, PluginHost::IShell::state& state) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = Core::ERROR_NONE; - state = interface->State(); - std::cout << "IShell state " << state << " for " << callsign << std::endl; - interface->Release(); - } - return result; - } - uint32_t activate(PluginHost::IShell* shell, const string& callsign) - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - Core::Event event(false, true); -#ifndef USE_THUNDER_R4 - Core::IWorkerPool::Instance().Submit(Core::ProxyType>(Core::ProxyType::Create([&]() { -#else - Core::IWorkerPool::Instance().Submit(Core::ProxyType(Core::ProxyType::Create([&]() { -#endif /* USE_THUNDER_R4 */ - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = interface->Activate(PluginHost::IShell::reason::REQUESTED); - std::cout << "IShell activate status " << result << " for " << callsign << std::endl; - interface->Release(); - } - event.SetEvent(); - }))); - event.Lock(); - return result; - } - uint32_t deactivate(PluginHost::IShell* shell, const string& callsign) - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - Core::Event event(false, true); -#ifndef USE_THUNDER_R4 - Core::IWorkerPool::Instance().Submit(Core::ProxyType>(Core::ProxyType::Create([&]() { -#else - Core::IWorkerPool::Instance().Submit(Core::ProxyType(Core::ProxyType::Create([&]() { -#endif /* USE_THUNDER_R4 */ - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = interface->Deactivate(PluginHost::IShell::reason::REQUESTED); - std::cout << "IShell deactivate status " << result << " for " << callsign << std::endl; - interface->Release(); - } - event.SetEvent(); - }))); - event.Lock(); - return result; - } - } - - struct JSONRPCDirectLink - { - private: - uint32_t mId { 0 }; - std::string mCallSign { }; -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - PluginHost::ILocalDispatcher * dispatcher_ {nullptr}; -#else - PluginHost::IDispatcher * dispatcher_ {nullptr}; -#endif - - Core::ProxyType Message() const - { - return (Core::ProxyType(PluginHost::IFactories::Instance().JSONRPC())); - } - - template - bool ToMessage(PARAMETERS& parameters, Core::ProxyType& message) const - { - return ToMessage((Core::JSON::IElement*)(¶meters), message); - } - bool ToMessage(Core::JSON::IElement* parameters, Core::ProxyType& message) const - { - if (!parameters->IsSet()) - return true; - string values; - if (!parameters->ToString(values)) - { - std::cout << "Failed to convert params to string\n"; - return false; - } - if (values.empty() != true) - { - message->Parameters = values; - } - return true; - } - template - bool FromMessage(RESPONSE& response, const Core::ProxyType& message, bool isResponseString=false) const - { - return FromMessage((Core::JSON::IElement*)(&response), message, isResponseString); - } - bool FromMessage(Core::JSON::IElement* response, const Core::ProxyType& message, bool isResponseString=false) const - { - Core::OptionalType error; - if ( !isResponseString && !response->FromString(message->Result.Value(), error) ) - { - std::cout << "Failed to parse response!!! Error: '" << error.Value().Message() << "'\n"; - return false; - } - return true; - } - - public: - JSONRPCDirectLink(PluginHost::IShell* service, std::string callsign) - : mCallSign(callsign) - { - if (service) -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - dispatcher_ = service->QueryInterfaceByCallsign(mCallSign); -#else - dispatcher_ = service->QueryInterfaceByCallsign(mCallSign); -#endif - } - - JSONRPCDirectLink(PluginHost::IShell* service) - : JSONRPCDirectLink(service, "Controller") - { - } - ~JSONRPCDirectLink() - { - if (dispatcher_) - dispatcher_->Release(); - } - - template - uint32_t Get(const uint32_t waitTime, const string& method, PARAMETERS& respObject) - { - JsonObject empty; - return Invoke(waitTime, method, empty, respObject); - } - - template - uint32_t Set(const uint32_t waitTime, const string& method, const PARAMETERS& sendObject) - { - JsonObject empty; - return Invoke(waitTime, method, sendObject, empty); - } - - template - uint32_t Invoke(const uint32_t waitTime, const string& method, const PARAMETERS& parameters, RESPONSE& response, bool isResponseString=false) - { - if (dispatcher_ == nullptr) { - std::cout << "No JSON RPC dispatcher for " << mCallSign << '\n'; - return Core::ERROR_GENERAL; - } - - auto message = Message(); - - message->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - message->Id = Core::JSON::DecUInt32(++mId); - message->Designator = Core::JSON::String(mCallSign + ".1." + method); - - ToMessage(parameters, message); - - const uint32_t channelId = ~0; -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - string output = ""; - uint32_t result = Core::ERROR_BAD_REQUEST; - - if (dispatcher_ != nullptr) { - PluginHost::ILocalDispatcher* localDispatcher = dispatcher_->Local(); - - ASSERT(localDispatcher != nullptr); - - if (localDispatcher != nullptr) - result = dispatcher_->Invoke(channelId, message->Id.Value(), sThunderSecurityToken, message->Designator.Value(), message->Parameters.Value(),output); - } - - if (message.IsValid() == true) { - if (result == static_cast(~0)) { - message.Release(); - } - else if (result == Core::ERROR_NONE) - { - if (output.empty() == true) - message->Result.Null(true); - else - message->Result = output; - } - else - { - message->Error.SetError(result); - if (output.empty() == false) { - message->Error.Text = output; - } - } - } - - if (!FromMessage(response, message, isResponseString)) - { - return Core::ERROR_GENERAL; - } -#elif (THUNDER_VERSION == 2) - auto resp = dispatcher_->Invoke(sThunderSecurityToken, channelId, *message); -#else - Core::JSONRPC::Context context(channelId, message->Id.Value(), sThunderSecurityToken) ; - auto resp = dispatcher_->Invoke(context, *message); -#endif - -#if ((THUNDER_VERSION == 2) || (THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 2)) - - if (resp->Error.IsSet()) { - std::cout << "Call failed: " << message->Designator.Value() << " error: " << resp->Error.Text.Value() << "\n"; - return resp->Error.Code; - } - - if (!FromMessage(response, resp, isResponseString)) - return Core::ERROR_GENERAL; -#endif - return Core::ERROR_NONE; - } - }; - - class StateControlNotification: public PluginHost::IStateControl::INotification - { - RDKShell& mRDKShell; - std::string mCallSign; - bool mLaunchEnabled { false }; - public: - StateControlNotification(std::string callsign, RDKShell& shell) - : mRDKShell(shell) - , mCallSign(callsign) - { - } - - void enableLaunch(bool enable) - { - mLaunchEnabled = enable; - } - - void StateChange(const PluginHost::IStateControl::state state) override - { - bool isSuspended = (state == PluginHost::IStateControl::SUSPENDED); - if (mLaunchEnabled) - { - JsonObject params; - params["client"] = mCallSign; - params["launchType"] = (isSuspended)?"suspend":"resume"; - mRDKShell.notify(RDKShell::RDKSHELL_EVENT_ON_LAUNCHED, params); - mLaunchEnabled = false; - } -#ifdef HIBERNATE_SUPPORT_ENABLED - gSuspendedOrHibernatedApplicationsMutex.lock(); - gSuspendedOrHibernatedApplications[mCallSign] = isSuspended; - gSuspendedOrHibernatedApplicationsMutex.unlock(); -#endif - - if (isSuspended) - { - JsonObject params; - params["client"] = mCallSign; - mRDKShell.notify(RDKShell::RDKSHELL_EVENT_ON_PLUGIN_SUSPENDED, params); - -#ifdef HIBERNATE_NATIVE_APPS_ON_SUSPENDED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.AppHibernate.Enable", param) - && strncasecmp(param.value, "true", 4) == 0) - { - gLaunchedToSuspendedMutex.lock(); - bool l2s = (gLaunchedToSuspended.find(mCallSign) != gLaunchedToSuspended.end()); - gLaunchedToSuspendedMutex.unlock(); - - if (!l2s && (mCallSign.find("Netflix") != std::string::npos || mCallSign.find("Cobalt") != std::string::npos || mCallSign.find("Amazon") != std::string::npos || mCallSign.find("YouTube") != std::string::npos)) - { - // call RDKShell.hibernate - std::thread requestsThread = - std::thread([=]() - { - JsonObject hibernateParams; - JsonObject hibernatetResponse; - hibernateParams["callsign"] = mCallSign; - mRDKShell.getThunderControllerClient("org.rdk.RDKShell.1")->Invoke(0, "hibernate", hibernateParams, hibernatetResponse); }); - - requestsThread.detach(); - } - } -#endif - } - - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(PluginHost::IStateControl::INotification) - END_INTERFACE_MAP - }; - - std::map gStateNotifications; - - struct RDKShellStartupConfig - { - std::string rfc; - std::string thunderApi; - JsonObject params; - }; - - std::map gActivePluginsData; - std::map gPluginsEventListener; - std::vector gStartupConfigs; - std::map gDestroyApplications; - std::map gExternalDestroyApplications; - std::map gLaunchApplications; - std::map gApplicationsExitReason; - std::map gPluginDisplayNameMap; - - uint32_t getKeyFlag(std::string modifier) - { - uint32_t flag = 0; - if (0 == modifier.compare("ctrl")) - { - flag = RDKSHELL_FLAGS_CONTROL; - } - else if (0 == modifier.compare("shift")) - { - flag = RDKSHELL_FLAGS_SHIFT; - } - else if (0 == modifier.compare("alt")) - { - flag = RDKSHELL_FLAGS_ALT; - } - return flag; - } - - SERVICE_REGISTRATION(RDKShell, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - RDKShell* RDKShell::_instance = nullptr; - std::mutex gRdkShellMutex; - std::mutex gPluginDataMutex; - std::mutex gLaunchDestroyMutex; - std::mutex gDestroyMutex; - - std::mutex gLaunchMutex; - std::mutex gExitReasonMutex; - std::mutex gSubscribeMutex; - int32_t gLaunchCount = 0; - - static std::thread shellThread; - - struct CreateDisplayRequest - { - CreateDisplayRequest(std::string client, std::string displayName, uint32_t displayWidth=0, uint32_t displayHeight=0, bool virtualDisplayEnabled=false, uint32_t virtualWidth=0, uint32_t virtualHeight=0, bool topmost = false, bool focus = false): mClient(client), mDisplayName(displayName), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight), mVirtualDisplayEnabled(virtualDisplayEnabled), mVirtualWidth(virtualWidth),mVirtualHeight(virtualHeight), mTopmost(topmost), mFocus(focus), mResult(false) , mAutoDestroy(true) - { - sem_init(&mSemaphore, 0, 0); - } - - ~CreateDisplayRequest() - { - sem_destroy(&mSemaphore); - } - - std::string mClient; - std::string mDisplayName; - uint32_t mDisplayWidth; - uint32_t mDisplayHeight; - bool mVirtualDisplayEnabled; - uint32_t mVirtualWidth; - uint32_t mVirtualHeight; - bool mTopmost; - bool mFocus; - sem_t mSemaphore; - bool mResult; - bool mAutoDestroy; - }; - - struct KillClientRequest - { - KillClientRequest(std::string client): mClient(client), mResult(false) - { - sem_init(&mSemaphore, 0, 0); - } - - ~KillClientRequest() - { - sem_destroy(&mSemaphore); - } - - std::string mClient; - sem_t mSemaphore; - bool mResult; - }; - - std::vector> gCreateDisplayRequests; - std::vector> gKillClientRequests; - - void RDKShell::launchRequestThread(RDKShellApiRequest apiRequest) - { - std::thread rdkshellRequestsThread = std::thread([=]() { - JsonObject result; - std::string requestName = apiRequest.mName; - if (requestName.compare("launchFactoryApp") == 0) - { - launchFactoryAppWrapper(apiRequest.mRequest, result); - } - else if (requestName.compare("launchResidentApp") == 0) - { - launchResidentAppWrapper(apiRequest.mRequest, result); - } - else if (requestName.compare("toggleFactoryApp") == 0) - { - toggleFactoryAppWrapper(apiRequest.mRequest, result); - } - else if (requestName.compare("exitAgingMode") == 0) - { - exitAgingModeWrapper(apiRequest.mRequest, result); - } - else if (requestName.compare("launchFactoryAppShortcut") == 0) - { - launchFactoryAppShortcutWrapper(apiRequest.mRequest, result); - } - else if (requestName.compare("deactivateresidentapp") == 0) - { - auto deactivateStatus = deactivate(mCurrentService, "ResidentApp"); - std::cout << "deactivating resident app status " << deactivateStatus << std::endl; - } - else if (requestName.compare("susbscribeSystemEvent") == 0) - { - gSubscribeMutex.lock(); - subscribeForSystemEvent("onSystemPowerStateChanged"); - gSubscribeMutex.unlock(); - std::cout << "subscribed system event " << std::endl; - JsonObject joGetParams; - JsonObject joGetResult; - joGetParams["params"] = JsonObject(); - std::string getPowerStateInvoke = "org.rdk.System.1.getPowerState"; - auto thunderController = getThunderControllerClient(); - thunderController->Invoke(5000, getPowerStateInvoke.c_str(), joGetParams, joGetResult); - const std::string currentPowerState = joGetResult["powerState"].String(); - if (currentPowerState == "ON") - { - JsonObject request, response; - request["callsign"] = "ResidentApp"; - request["visible"] = true; - getThunderControllerClient("org.rdk.RDKShell.1")->Invoke(0, "setVisibility", request, response); - } - } - else - { - std::string api("org.rdk.RDKShell.1."); - api.append(requestName); - auto thunderController = getThunderControllerClient(); - JsonObject joResult; - thunderController->Invoke(RDKSHELL_THUNDER_TIMEOUT, api.c_str(), apiRequest.mRequest, joResult); - } - }); - rdkshellRequestsThread.detach(); - } - - void lockRdkShellMutex() - { - bool lockAcquired = false; - double startTime = RdkShell::milliseconds(); - while (!lockAcquired && (RdkShell::milliseconds() - startTime) < RDKSHELL_TRY_LOCK_WAIT_TIME_IN_MS) - { - lockAcquired = gRdkShellMutex.try_lock(); - } - if (!lockAcquired) - { - std::cout << "unable to get lock for defaulting to normal lock\n"; - gRdkShellMutex.lock(); - } - /*else - { - std::cout << "lock was acquired via try\n"; - }*/ - } - - static bool isClientExists(std::string client) - { - bool exist = false; - lockRdkShellMutex(); - for (unsigned int i=0; imClient.compare(client) == 0) - { - exist = true; - break; - } - } - gRdkShellMutex.unlock(); - - if (!exist) - { - std::vector clientList; - lockRdkShellMutex(); - CompositorController::getClients(clientList); - gRdkShellMutex.unlock(); - std::string newClient(client); - transform(newClient.begin(), newClient.end(), newClient.begin(), ::tolower); - if (std::find(clientList.begin(), clientList.end(), newClient) != clientList.end()) - { - exist = true; - } - } - return exist; - } - - static void updateSurfaceClientIdentifiers(PluginHost::IShell* shell) - { - uint32_t status = 0; - auto thunderController = RDKShell::getThunderControllerClient(); - string configString; - Core::JSON::ArrayType availablePluginResult; - status = thunderController->Get>(RDKSHELL_THUNDER_TIMEOUT, "status", availablePluginResult); - if(status > 0) - { - std::cout<<"pluginfo status falied"< 0) - { - std::cout<<"clientidentifier config set failed"<ConfigLine(); - if (configLine.empty()) - { - return; - } - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string clientidentifier = serviceConfig["clientidentifier"].String(); - std::string serviceCallsign = service->Callsign(); - if ((serviceCallsign == RESIDENTAPP_CALLSIGN) && ignoreResidentAppLaunch()) - { - std::cout << "Resident app activation early !!! " << std::endl; - return; - } - if (!isClientExists(serviceCallsign)) - { - std::shared_ptr request = std::make_shared(serviceCallsign, clientidentifier); - gRdkShellMutex.lock(); - gCreateDisplayRequests.push_back(request); - gRdkShellMutex.unlock(); - sem_wait(&request->mSemaphore); - } - gRdkShellMutex.lock(); - RdkShell::CompositorController::addListener(service->Callsign(), mShell.mEventListener); - gRdkShellMutex.unlock(); - gPluginDataMutex.lock(); - std::string className = service->ClassName(); - PluginData pluginData; - pluginData.mClassName = className; - if (gActivePluginsData.find(serviceCallsign) == gActivePluginsData.end()) - { - gActivePluginsData[serviceCallsign] = pluginData; - } - gPluginDataMutex.unlock(); - } - } - } - - void RDKShell::MonitorClients::handleActivated(PluginHost::IShell* service) - { - if(service) - { - if(service->Callsign() == RESIDENTAPP_CALLSIGN) - { - bool ignoreLaunch = ignoreResidentAppLaunch(true); - if (ignoreLaunch) - { - std::cout << "deactivating resident app as factory mode is set" << std::endl; - JsonObject destroyRequest; - destroyRequest["callsign"] = "ResidentApp"; - RDKShellApiRequest apiRequest; - apiRequest.mName = "destroy"; - apiRequest.mRequest = destroyRequest; - RDKShell* rdkshellPlugin = RDKShell::_instance; - rdkshellPlugin->launchRequestThread(apiRequest); - } - } - else if(service->Callsign() == PERSISTENT_STORE_CALLSIGN && !sPersistentStoreFirstActivated) - { - std::cout << "persistent store activated\n"; - gRdkShellMutex.lock(); - sPersistentStoreFirstActivated = true; - gRdkShellMutex.unlock(); - } - else if(service->Callsign() == SYSTEM_SERVICE_CALLSIGN) - { - RDKShellApiRequest apiRequest; - apiRequest.mName = "susbscribeSystemEvent"; - RDKShell* rdkshellPlugin = RDKShell::_instance; - rdkshellPlugin->launchRequestThread(apiRequest); - } - } - } - - void RDKShell::MonitorClients::handleDeactivated(PluginHost::IShell* service) - { - if (service) - { - gLaunchDestroyMutex.lock(); - if (gDestroyApplications.find(service->Callsign()) == gDestroyApplications.end()) - { - gExternalDestroyApplications[service->Callsign()] = true; - } - gLaunchDestroyMutex.unlock(); - StateControlNotification* notification = nullptr; - gPluginDataMutex.lock(); - auto notificationIt = gStateNotifications.find(service->Callsign()); - if (notificationIt != gStateNotifications.end()) - { - notification = notificationIt->second; - gStateNotifications.erase(notificationIt); - } - gPluginDataMutex.unlock(); - if (notification) - { - PluginHost::IStateControl* stateControl(service->QueryInterface()); - if (stateControl != nullptr) - { - stateControl->Unregister(notification); - stateControl->Release(); - } - notification->Release(); - } - gExitReasonMutex.lock(); - gApplicationsExitReason[service->Callsign()] = AppLastExitReason::DEACTIVATED; - -#ifdef HIBERNATE_SUPPORT_ENABLED - //Reset app suspended/hibernated - gSuspendedOrHibernatedApplicationsMutex.lock(); - auto suspendedOrHibernatedIt = gSuspendedOrHibernatedApplications.find(service->Callsign()); - if (suspendedOrHibernatedIt != gSuspendedOrHibernatedApplications.end()) - { - gSuspendedOrHibernatedApplications.erase(suspendedOrHibernatedIt); - } - gSuspendedOrHibernatedApplicationsMutex.unlock(); -#endif - if(service->Reason() == PluginHost::IShell::FAILURE) - { - gApplicationsExitReason[service->Callsign()] = AppLastExitReason::CRASH; - } - gExitReasonMutex.unlock(); - } - } - - void RDKShell::MonitorClients::handleDeinitialized(PluginHost::IShell* service) - { - if (service) - { - std::string configLine = service->ConfigLine(); - if (configLine.empty()) - { - return; - } - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string clientidentifier = serviceConfig["clientidentifier"].String(); - std::shared_ptr request = std::make_shared(service->Callsign()); - gRdkShellMutex.lock(); - gKillClientRequests.push_back(request); - gRdkShellMutex.unlock(); - sem_wait(&request->mSemaphore); - gRdkShellMutex.lock(); - RdkShell::CompositorController::removeListener(service->Callsign(), mShell.mEventListener); - gRdkShellMutex.unlock(); - } - - gPluginDataMutex.lock(); - std::map::iterator pluginToRemove = gActivePluginsData.find(service->Callsign()); - if (pluginToRemove != gActivePluginsData.end()) - { - gActivePluginsData.erase(pluginToRemove); - } - std::map::iterator pluginStateChangeEntry = gPluginsEventListener.find(service->Callsign()); - if (pluginStateChangeEntry != gPluginsEventListener.end()) - { - PluginStateChangeData* stateChangeData = pluginStateChangeEntry->second; - if (nullptr != stateChangeData) - { - stateChangeData->resetConnection(); - delete stateChangeData; - } - pluginStateChangeEntry->second = nullptr; - gPluginsEventListener.erase(pluginStateChangeEntry); - } - gPluginDataMutex.unlock(); - gLaunchDestroyMutex.lock(); - if (gExternalDestroyApplications.find(service->Callsign()) != gExternalDestroyApplications.end()) - { - gExternalDestroyApplications.erase(service->Callsign()); - } - gLaunchDestroyMutex.unlock(); - } - } - - void RDKShell::MonitorClients::StateChange(PluginHost::IShell* service) - { - if (service) - { - PluginHost::IShell::state currentState(service->State()); - - gExitReasonMutex.lock(); - if ((currentState == PluginHost::IShell::DEACTIVATED) || (currentState == PluginHost::IShell::DESTROYED)) - { - gApplicationsExitReason[service->Callsign()] = AppLastExitReason::DEACTIVATED; -#ifdef HIBERNATE_SUPPORT_ENABLED - //Reset app suspended/hibernated on Deactivation/Destroy - gSuspendedOrHibernatedApplicationsMutex.lock(); - auto suspendedOrHibernatedIt = gSuspendedOrHibernatedApplications.find(service->Callsign()); - if (suspendedOrHibernatedIt != gSuspendedOrHibernatedApplications.end()) - { - gSuspendedOrHibernatedApplications.erase(suspendedOrHibernatedIt); - } - gSuspendedOrHibernatedApplicationsMutex.unlock(); -#endif - } - if(service->Reason() == PluginHost::IShell::FAILURE) - { - gApplicationsExitReason[service->Callsign()] = AppLastExitReason::CRASH; - } - gExitReasonMutex.unlock(); - - if (currentState == PluginHost::IShell::ACTIVATION) - { - std::string configLine = service->ConfigLine(); - if (configLine.empty()) - { - return; - } - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string clientidentifier = serviceConfig["clientidentifier"].String(); - std::string serviceCallsign = service->Callsign(); - if ((serviceCallsign == RESIDENTAPP_CALLSIGN) && ignoreResidentAppLaunch()) - { - std::cout << "Resident app activation early !!! " << std::endl; - return; - } - if (!isClientExists(serviceCallsign)) - { - std::shared_ptr request = std::make_shared(serviceCallsign, clientidentifier); - gRdkShellMutex.lock(); - gCreateDisplayRequests.push_back(request); - gRdkShellMutex.unlock(); - sem_wait(&request->mSemaphore); - } - gRdkShellMutex.lock(); - RdkShell::CompositorController::addListener(service->Callsign(), mShell.mEventListener); - gRdkShellMutex.unlock(); - gPluginDataMutex.lock(); - std::string className = service->ClassName(); - PluginData pluginData; - pluginData.mClassName = className; - if (gActivePluginsData.find(serviceCallsign) == gActivePluginsData.end()) - { - gActivePluginsData[serviceCallsign] = pluginData; - } - gPluginDataMutex.unlock(); - } - } - else if (currentState == PluginHost::IShell::ACTIVATED && service->Callsign() == WPEFramework::Plugin::RDKShell::SERVICE_NAME) - { - /*PluginHost::ISubSystem* subSystems(service->SubSystems()); - if (subSystems != nullptr) - { - subSystems->Set(PluginHost::ISubSystem::PLATFORM, nullptr); - subSystems->Set(PluginHost::ISubSystem::GRAPHICS, nullptr); - subSystems->Release(); - }*/ - } - else if (currentState == PluginHost::IShell::ACTIVATED && service->Callsign() == RESIDENTAPP_CALLSIGN) - { - bool ignoreLaunch = ignoreResidentAppLaunch(true); - if (ignoreLaunch) - { - std::cout << "deactivating resident app as factory mode is set" << std::endl; - JsonObject destroyRequest; - destroyRequest["callsign"] = "ResidentApp"; - RDKShellApiRequest apiRequest; - apiRequest.mName = "destroy"; - apiRequest.mRequest = destroyRequest; - RDKShell* rdkshellPlugin = RDKShell::_instance; - rdkshellPlugin->launchRequestThread(apiRequest); - } - } - else if (currentState == PluginHost::IShell::ACTIVATED && service->Callsign() == PERSISTENT_STORE_CALLSIGN && !sPersistentStoreFirstActivated) - { - std::cout << "persistent store activated\n"; - gRdkShellMutex.lock(); - sPersistentStoreFirstActivated = true; - gRdkShellMutex.unlock(); - } - else if (currentState == PluginHost::IShell::ACTIVATED && service->Callsign() == SYSTEM_SERVICE_CALLSIGN) - { - RDKShellApiRequest apiRequest; - apiRequest.mName = "susbscribeSystemEvent"; - RDKShell* rdkshellPlugin = RDKShell::_instance; - rdkshellPlugin->launchRequestThread(apiRequest); - } - else if (currentState == PluginHost::IShell::DEACTIVATION) - { - gLaunchDestroyMutex.lock(); - if (gDestroyApplications.find(service->Callsign()) == gDestroyApplications.end()) - { - gExternalDestroyApplications[service->Callsign()] = true; - } - gLaunchDestroyMutex.unlock(); - StateControlNotification* notification = nullptr; - gPluginDataMutex.lock(); - auto notificationIt = gStateNotifications.find(service->Callsign()); - if (notificationIt != gStateNotifications.end()) - { - notification = notificationIt->second; - gStateNotifications.erase(notificationIt); - } - gPluginDataMutex.unlock(); - if (notification) - { - PluginHost::IStateControl* stateControl(service->QueryInterface()); - if (stateControl != nullptr) - { - stateControl->Unregister(notification); - stateControl->Release(); - } - notification->Release(); - } - } - else if ((currentState == PluginHost::IShell::DEACTIVATED)) - { - std::string configLine = service->ConfigLine(); - if (configLine.empty()) - { - return; - } - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string clientidentifier = serviceConfig["clientidentifier"].String(); - std::shared_ptr request = std::make_shared(service->Callsign()); - gRdkShellMutex.lock(); - gKillClientRequests.push_back(request); - gRdkShellMutex.unlock(); - sem_wait(&request->mSemaphore); - gRdkShellMutex.lock(); - RdkShell::CompositorController::removeListener(service->Callsign(), mShell.mEventListener); - gRdkShellMutex.unlock(); - } - - gPluginDataMutex.lock(); - std::map::iterator pluginToRemove = gActivePluginsData.find(service->Callsign()); - if (pluginToRemove != gActivePluginsData.end()) - { - gActivePluginsData.erase(pluginToRemove); - } - std::map::iterator pluginStateChangeEntry = gPluginsEventListener.find(service->Callsign()); - if (pluginStateChangeEntry != gPluginsEventListener.end()) - { - PluginStateChangeData* stateChangeData = pluginStateChangeEntry->second; - if (nullptr != stateChangeData) - { - stateChangeData->resetConnection(); - delete stateChangeData; - } - pluginStateChangeEntry->second = nullptr; - gPluginsEventListener.erase(pluginStateChangeEntry); - } - gPluginDataMutex.unlock(); - gLaunchDestroyMutex.lock(); - if (gExternalDestroyApplications.find(service->Callsign()) != gExternalDestroyApplications.end()) - { - gExternalDestroyApplications.erase(service->Callsign()); - } - gLaunchDestroyMutex.unlock(); - } - } - } - -#ifdef USE_THUNDER_R4 - void RDKShell::MonitorClients::Initialize(const string& callsign, PluginHost::IShell* service) - { - handleInitialize(service); - } - void RDKShell::MonitorClients::Activation(const string& callsign, PluginHost::IShell* service) - {} - void RDKShell::MonitorClients::Activated(const string& callsign, PluginHost::IShell* service) - { - handleActivated(service); - } - void RDKShell::MonitorClients::Deactivation(const string& callsign, PluginHost::IShell* service) - {} - void RDKShell::MonitorClients::Deactivated(const string& callsign, PluginHost::IShell* service) - { - //StateChange(service); - handleDeactivated(service); - } - void RDKShell::MonitorClients::Deinitialized(const string& callsign, PluginHost::IShell* service) - { - handleDeinitialized(service); - } - void RDKShell::MonitorClients::Unavailable(const string& callsign, PluginHost::IShell* service) - {} -#endif /* USE_THUNDER_R4 */ - - bool RDKShell::ScreenCapture::Capture(ICapture::IStore& storer) - { - mCaptureStorers.push_back(&storer); - - JsonObject parameters, response; - mShell->getScreenshotWrapper(parameters, response); - return true; - } - - void RDKShell::ScreenCapture::onScreenCapture(const unsigned char *data, unsigned int width, unsigned int height) - { - if (mCaptureStorers.size() > 0) - { - for (unsigned int n = 0; n < mCaptureStorers.size(); n++) - { - mCaptureStorers[n]->R8_G8_B8_A8(data, width, height); - } - mCaptureStorers.clear(); - } - } - - RDKShell::RDKShell() - : PluginHost::JSONRPC(), - mEnableUserInactivityNotification(true), - mClientsMonitor(Core::Service::Create(this)), - mCurrentService(nullptr), mLastWakeupKeyCode(0), - mLastWakeupKeyModifiers(0), - mLastWakeupKeyTimestamp(0), - mEnableEasterEggs(true), - mScreenCapture(this), - mErmEnabled(false), - mTaskQueue() - { - LOGINFO("ctor"); - RDKShell::_instance = this; - mEventListener = std::make_shared(this); - - mRemoteShell = false; - Register(RDKSHELL_METHOD_MOVE_TO_FRONT, &RDKShell::moveToFrontWrapper, this); - Register(RDKSHELL_METHOD_MOVE_TO_BACK, &RDKShell::moveToBackWrapper, this); - Register(RDKSHELL_METHOD_MOVE_BEHIND, &RDKShell::moveBehindWrapper, this); - Register(RDKSHELL_METHOD_SET_FOCUS, &RDKShell::setFocusWrapper, this); - Register(RDKSHELL_METHOD_GET_FOCUSED, &RDKShell::getFocusedWrapper, this); - Register(RDKSHELL_METHOD_KILL, &RDKShell::killWrapper, this); - Register(RDKSHELL_METHOD_ADD_KEY_INTERCEPT, &RDKShell::addKeyInterceptWrapper, this); - Register(RDKSHELL_METHOD_ADD_KEY_INTERCEPTS, &RDKShell::addKeyInterceptsWrapper, this); - Register(RDKSHELL_METHOD_REMOVE_KEY_INTERCEPT, &RDKShell::removeKeyInterceptWrapper, this); - Register(RDKSHELL_METHOD_ADD_KEY_LISTENER, &RDKShell::addKeyListenersWrapper, this); - Register(RDKSHELL_METHOD_REMOVE_KEY_LISTENER, &RDKShell::removeKeyListenersWrapper, this); - Register(RDKSHELL_METHOD_ADD_KEY_METADATA_LISTENER, &RDKShell::addKeyMetadataListenerWrapper, this); - Register(RDKSHELL_METHOD_REMOVE_KEY_METADATA_LISTENER, &RDKShell::removeKeyMetadataListenerWrapper, this); - Register(RDKSHELL_METHOD_INJECT_KEY, &RDKShell::injectKeyWrapper, this); - Register(RDKSHELL_METHOD_GENERATE_KEYS, &RDKShell::generateKeyWrapper, this); - Register(RDKSHELL_METHOD_GET_SCREEN_RESOLUTION, &RDKShell::getScreenResolutionWrapper, this); - Register(RDKSHELL_METHOD_SET_SCREEN_RESOLUTION, &RDKShell::setScreenResolutionWrapper, this); - Register(RDKSHELL_METHOD_CREATE_DISPLAY, &RDKShell::createDisplayWrapper, this); - Register(RDKSHELL_METHOD_GET_CLIENTS, &RDKShell::getClientsWrapper, this); - Register(RDKSHELL_METHOD_GET_Z_ORDER, &RDKShell::getZOrderWrapper, this); - Register(RDKSHELL_METHOD_GET_BOUNDS, &RDKShell::getBoundsWrapper, this); - Register(RDKSHELL_METHOD_SET_BOUNDS, &RDKShell::setBoundsWrapper, this); - Register(RDKSHELL_METHOD_GET_VISIBILITY, &RDKShell::getVisibilityWrapper, this); - Register(RDKSHELL_METHOD_SET_VISIBILITY, &RDKShell::setVisibilityWrapper, this); - Register(RDKSHELL_METHOD_GET_OPACITY, &RDKShell::getOpacityWrapper, this); - Register(RDKSHELL_METHOD_SET_OPACITY, &RDKShell::setOpacityWrapper, this); - Register(RDKSHELL_METHOD_GET_SCALE, &RDKShell::getScaleWrapper, this); - Register(RDKSHELL_METHOD_SET_SCALE, &RDKShell::setScaleWrapper, this); - Register(RDKSHELL_METHOD_GET_HOLE_PUNCH, &RDKShell::getHolePunchWrapper, this); - Register(RDKSHELL_METHOD_SET_HOLE_PUNCH, &RDKShell::setHolePunchWrapper, this); - Register(RDKSHELL_METHOD_GET_LOG_LEVEL, &RDKShell::getLogLevelWrapper, this); - Register(RDKSHELL_METHOD_SET_LOG_LEVEL, &RDKShell::setLogLevelWrapper, this); - Register(RDKSHELL_METHOD_SHOW_SPLASH_LOGO, &RDKShell::showSplashLogoWrapper, this); - Register(RDKSHELL_METHOD_HIDE_SPLASH_LOGO, &RDKShell::hideSplashLogoWrapper, this); - Register(RDKSHELL_METHOD_REMOVE_ANIMATION, &RDKShell::removeAnimationWrapper, this); - Register(RDKSHELL_METHOD_ADD_ANIMATION, &RDKShell::addAnimationWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_INACTIVITY_REPORTING, &RDKShell::enableInactivityReportingWrapper, this); - Register(RDKSHELL_METHOD_SET_INACTIVITY_INTERVAL, &RDKShell::setInactivityIntervalWrapper, this); - Register(RDKSHELL_METHOD_RESET_INACTIVITY_TIME, &RDKShell::resetInactivityTimeWrapper, this); - Register(RDKSHELL_METHOD_SCALE_TO_FIT, &RDKShell::scaleToFitWrapper, this); - Register(RDKSHELL_METHOD_LAUNCH, &RDKShell::launchWrapper, this); - Register(RDKSHELL_METHOD_LAUNCH_APP, &RDKShell::launchApplicationWrapper, this); - Register(RDKSHELL_METHOD_SUSPEND, &RDKShell::suspendWrapper, this); - Register(RDKSHELL_METHOD_SUSPEND_APP, &RDKShell::suspendApplicationWrapper, this); - Register(RDKSHELL_METHOD_RESUME_APP, &RDKShell::resumeApplicationWrapper, this); - Register(RDKSHELL_METHOD_DESTROY, &RDKShell::destroyWrapper, this); - Register(RDKSHELL_METHOD_GET_AVAILABLE_TYPES, &RDKShell::getAvailableTypesWrapper, this); - Register(RDKSHELL_METHOD_GET_STATE, &RDKShell::getState, this); - Register(RDKSHELL_METHOD_GET_SYSTEM_MEMORY, &RDKShell::getSystemMemoryWrapper, this); - Register(RDKSHELL_METHOD_GET_SYSTEM_RESOURCE_INFO, &RDKShell::getSystemResourceInfoWrapper, this); - Register(RDKSHELL_METHOD_SET_MEMORY_MONITOR, &RDKShell::setMemoryMonitorWrapper, this); - Register(RDKSHELL_METHOD_SHOW_WATERMARK, &RDKShell::showWatermarkWrapper, this); - Register(RDKSHELL_METHOD_SHOW_FULL_SCREEN_IMAGE, &RDKShell::showFullScreenImageWrapper, this); - Register(RDKSHELL_METHOD_HIDE_FULL_SCREEN_IMAGE, &RDKShell::hideFullScreenImageWrapper, this); - Register(RDKSHELL_METHOD_LAUNCH_FACTORY_APP, &RDKShell::launchFactoryAppWrapper, this); - Register(RDKSHELL_METHOD_LAUNCH_FACTORY_APP_SHORTCUT, &RDKShell::launchFactoryAppShortcutWrapper, this); - Register(RDKSHELL_METHOD_LAUNCH_RESIDENT_APP, &RDKShell::launchResidentAppWrapper, this); - Register(RDKSHELL_METHOD_TOGGLE_FACTORY_APP, &RDKShell::toggleFactoryAppWrapper, this); - Register(RDKSHELL_METHOD_EXIT_AGING_MODE, &RDKShell::exitAgingModeWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_KEYREPEATS, &RDKShell::enableKeyRepeatsWrapper, this); - Register(RDKSHELL_METHOD_GET_KEYREPEATS_ENABLED, &RDKShell::getKeyRepeatsEnabledWrapper, this); - Register(RDKSHELL_METHOD_SET_TOPMOST, &RDKShell::setTopmostWrapper, this); - Register(RDKSHELL_METHOD_GET_VIRTUAL_RESOLUTION, &RDKShell::getVirtualResolutionWrapper, this); - Register(RDKSHELL_METHOD_SET_VIRTUAL_RESOLUTION, &RDKShell::setVirtualResolutionWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_VIRTUAL_DISPLAY, &RDKShell::enableVirtualDisplayWrapper, this); - Register(RDKSHELL_METHOD_GET_VIRTUAL_DISPLAY_ENABLED, &RDKShell::getVirtualDisplayEnabledWrapper, this); - Register(RDKSHELL_METHOD_GET_LAST_WAKEUP_KEY, &RDKShell::getLastWakeupKeyWrapper, this); - Register(RDKSHELL_METHOD_HIDE_ALL_CLIENTS, &RDKShell::hideAllClientsWrapper, this); - Register(RDKSHELL_METHOD_GET_SCREENSHOT, &RDKShell::getScreenshotWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_EASTER_EGGS, &RDKShell::enableEasterEggsWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_LOGS_FLUSHING, &RDKShell::enableLogsFlushingWrapper, this); - Register(RDKSHELL_METHOD_GET_LOGS_FLUSHING_ENABLED, &RDKShell::getLogsFlushingEnabledWrapper, this); - Register(RDKSHELL_METHOD_IGNORE_KEY_INPUTS, &RDKShell::ignoreKeyInputsWrapper, this); - Register(RDKSHELL_METHOD_SHOW_CURSOR, &RDKShell::showCursorWrapper, this); - Register(RDKSHELL_METHOD_HIDE_CURSOR, &RDKShell::hideCursorWrapper, this); - Register(RDKSHELL_METHOD_GET_CURSOR_SIZE, &RDKShell::getCursorSizeWrapper, this); - Register(RDKSHELL_METHOD_SET_CURSOR_SIZE, &RDKShell::setCursorSizeWrapper, this); - Register(RDKSHELL_METHOD_ADD_EASTER_EGGS, &RDKShell::addEasterEggsWrapper, this); - Register(RDKSHELL_METHOD_REMOVE_EASTER_EGGS, &RDKShell::removeEasterEggsWrapper, this); - Register(RDKSHELL_METHOD_GET_EASTER_EGGS, &RDKShell::getEasterEggsWrapper, this); - Register(RDKSHELL_METHOD_ENABLE_INPUT_EVENTS, &RDKShell::enableInputEventsWrapper, this); - Register(RDKSHELL_METHOD_KEY_REPEAT_CONFIG, &RDKShell::keyRepeatConfigWrapper, this); - Register(RDKSHELL_METHOD_GET_GRAPHICS_FRAME_RATE, &RDKShell::getGraphicsFrameRateWrapper, this); - Register(RDKSHELL_METHOD_SET_GRAPHICS_FRAME_RATE, &RDKShell::setGraphicsFrameRateWrapper, this); - Register(RDKSHELL_METHOD_SET_AV_BLOCKED, &RDKShell::setAVBlockedWrapper, this); - Register(RDKSHELL_METHOD_GET_AV_BLOCKED_APPS, &RDKShell::getBlockedAVApplicationsWrapper, this); -#ifdef HIBERNATE_SUPPORT_ENABLED - Register(RDKSHELL_METHOD_HIBERNATE, &RDKShell::hibernateWrapper, this); - Register(RDKSHELL_METHOD_RESTORE, &RDKShell::restoreWrapper, this); -#endif - m_timer.connect(std::bind(&RDKShell::onTimer, this)); - } - - RDKShell::~RDKShell() - { - //LOGINFO("dtor"); - } - - const string RDKShell::Initialize(PluginHost::IShell* service ) - { - std::cout << "initializing\n"; - char* waylandDisplay = getenv("WAYLAND_DISPLAY"); - if (NULL != waylandDisplay) - { - std::cout << "RDKShell WAYLAND_DISPLAY is set to: " << waylandDisplay <<" unsetting WAYLAND_DISPLAY\n"; - unsetenv("WAYLAND_DISPLAY"); - } - else - { - std::cout << "RDKShell WAYLAND_DISPLAY is not set\n"; - } - - mCurrentService = service; - CompositorController::setEventListener(mEventListener); - bool factoryMacMatched = false; -#ifdef RFC_ENABLED - RFC_ParamData_t param; - bool ret = Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Power.UserInactivityNotification.Enable", param); - if (true == ret && param.type == WDMP_BOOLEAN && (strncasecmp(param.value,"true",4) == 0)) - { - mEnableUserInactivityNotification = true; - enableInactivityReporting(true); - ret = Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Power.UserInactivityNotification.TimeMinutes", param); - if (true == ret) - { - try - { - CompositorController::setInactivityInterval(std::stod(param.value)); - } - catch (...) - { - std::cout << "RDKShell unable to set inactivity interval " << std::endl; - } - } - } -#else - mEnableUserInactivityNotification = true; - enableInactivityReporting(true); -#endif - - // TODO: use interfaces and remove token - auto security = mCurrentService->QueryInterfaceByCallsign("SecurityAgent"); - if (security != nullptr) { - string payload = "http://localhost"; - string token; - if (security->CreateToken( - static_cast(payload.length()), - reinterpret_cast(payload.c_str()), - token) - == Core::ERROR_NONE) { - sThunderSecurityToken = token; - std::cout << "RDKShell got security token" << std::endl; - } else { - std::cout << "RDKShell failed to get security token" << std::endl; - } - security->Release(); - } else { - std::cout << "No security agent" << std::endl; - } - - service->Register(mClientsMonitor); - - static PluginHost::IShell* pluginService = nullptr; - pluginService = service; - - bool waitForPersistentStore = false; - char* waitValue = getenv("RDKSHELL_WAIT_FOR_PERSISTENT_STORE"); - if (NULL != waitValue) - { - std::cout << "waiting for persistent store\n"; - waitForPersistentStore = true; - } - if (factoryMacMatched) - { - waitForPersistentStore = false; - } - - char* blockResidentApp = getenv("RDKSHELL_BLOCK_RESIDENTAPP_FACTORYMODE"); - if (NULL != blockResidentApp) - { - std::cout << "block resident app on factory mode\n"; - sFactoryModeBlockResidentApp = true; - } - - mErmEnabled = CompositorController::isErmEnabled(); - sem_init(&gInitializeSemaphore, 0, 0); - shellThread = std::thread([=]() { - bool isRunning = true; - gRdkShellMutex.lock(); - RdkShell::initialize(); - if (!waitForPersistentStore) - { - PluginHost::ISubSystem* subSystems(pluginService->SubSystems()); - if (subSystems != nullptr) - { - std::cout << "setting platform and graphics\n"; - fflush(stdout); - RDKShell* rdkshellPlugin = RDKShell::_instance; - if (factoryMacMatched || ((nullptr != rdkshellPlugin) && (rdkshellPlugin->checkForBootupFactoryAppLaunch()))) - { - sFactoryModeStart = true; - } - subSystems->Set(PluginHost::ISubSystem::PLATFORM, nullptr); - subSystems->Set(PluginHost::ISubSystem::GRAPHICS, nullptr); - subSystems->Release(); - if (sFactoryModeStart) - { - JsonObject request, response; - std::cout << "about to launch factory app on start without persistent store wait\n"; - gRdkShellMutex.unlock(); - if (sFactoryModeBlockResidentApp) - { - request["nokillresapp"] = "true"; - } - request["resetagingtime"] = "true"; - RDKShellApiRequest apiRequest; - apiRequest.mName = "launchFactoryApp"; - apiRequest.mRequest = request; - rdkshellPlugin->launchRequestThread(apiRequest); - gRdkShellMutex.lock(); - } - else - { - std::cout << "not launching factory app as conditions not matched\n"; - } - } - } - isRunning = sRunning; - gRdkShellMutex.unlock(); - gRdkShellSurfaceModeEnabled = CompositorController::isSurfaceModeEnabled(); - sem_post(&gInitializeSemaphore); - while(isRunning) { - const double maxSleepTime = (1000 / gCurrentFramerate) * 1000; - double startFrameTime = RdkShell::microseconds(); - gRdkShellMutex.lock(); - if (!sPersistentStorePreLaunchChecked) - { - if (!sPersistentStoreFirstActivated) - { - PluginHost::IShell::state state; - getServiceState(mCurrentService, PERSISTENT_STORE_CALLSIGN, state); - if (state == PluginHost::IShell::state::ACTIVATED) { - sPersistentStoreFirstActivated = true; - } - } - sPersistentStorePreLaunchChecked = true; - } - - if (waitForPersistentStore && !sPersistentStoreWaitProcessed && sPersistentStoreFirstActivated) - { - PluginHost::ISubSystem* subSystems(pluginService->SubSystems()); - RDKShell* rdkshellPlugin = RDKShell::_instance; - if (subSystems != nullptr) - { - if ((nullptr != rdkshellPlugin) && rdkshellPlugin->checkForBootupFactoryAppLaunch()) - { - sFactoryModeStart = true; - } - std::cout << "setting platform and graphics after wait\n"; - subSystems->Set(PluginHost::ISubSystem::PLATFORM, nullptr); - subSystems->Set(PluginHost::ISubSystem::GRAPHICS, nullptr); - subSystems->Release(); - } - sPersistentStoreWaitProcessed = true; - if (sFactoryModeStart) - { - JsonObject request, response; - std::cout << "About to launch factory app after persistent store wait\n"; - gRdkShellMutex.unlock(); - if (sFactoryModeBlockResidentApp) - { - request["nokillresapp"] = "true"; - } - request["resetagingtime"] = "true"; - RDKShellApiRequest apiRequest; - apiRequest.mName = "launchFactoryApp"; - apiRequest.mRequest = request; - rdkshellPlugin->launchRequestThread(apiRequest); - gRdkShellMutex.lock(); - } - else - { - std::cout << "Not launching factory app as conditions not matched\n"; - } - } - while (gCreateDisplayRequests.size() > 0) - { - std::shared_ptr request = gCreateDisplayRequests.front(); - if (!request) - { - gCreateDisplayRequests.erase(gCreateDisplayRequests.begin()); - continue; - } - request->mResult = CompositorController::createDisplay(request->mClient, request->mDisplayName, request->mDisplayWidth, request->mDisplayHeight, request->mVirtualDisplayEnabled, request->mVirtualWidth, request->mVirtualHeight, request->mTopmost, request->mFocus , request->mAutoDestroy); - gCreateDisplayRequests.erase(gCreateDisplayRequests.begin()); - sem_post(&request->mSemaphore); - } - while (gKillClientRequests.size() > 0) - { - std::shared_ptr request = gKillClientRequests.front(); - if (!request) - { - gKillClientRequests.erase(gKillClientRequests.begin()); - continue; - } - request->mResult = CompositorController::kill(request->mClient); - gKillClientRequests.erase(gKillClientRequests.begin()); - sem_post(&request->mSemaphore); - } - if (receivedResolutionRequest) - { - CompositorController::setScreenResolution(resolutionWidth, resolutionHeight); - receivedResolutionRequest = false; - } - if (receivedFullScreenImageRequest) - { - CompositorController::showFullScreenImage(fullScreenImagePath); - fullScreenImagePath = ""; - receivedFullScreenImageRequest = false; - } - if (receivedShowWatermarkRequest) - { - CompositorController::showWatermark(); - receivedShowWatermarkRequest = false; - } - if (receivedShowSplashScreenRequest) - { - CompositorController::showSplashScreen(gSplashScreenDisplayTime); - gSplashScreenDisplayTime = 0; - receivedShowSplashScreenRequest = false; - } - RdkShell::draw(); - if (needsScreenshot) - { - uint8_t* data = nullptr; - uint32_t size; - string screenshotBase64; - CompositorController::screenShot(data, size); - Utils::String::imageEncoder(&data[0], size, true, screenshotBase64); - std::cout << "Screenshot success size:" << size << std::endl; - JsonObject params; - params["imageData"] = screenshotBase64; - - // Calling Notify instead of RDKShell::notify to avoid logging of entire screen content - LOGINFO("Notify %s", RDKSHELL_EVENT_ON_SCREENSHOT_COMPLETE.c_str()); - Notify(RDKSHELL_EVENT_ON_SCREENSHOT_COMPLETE, params); - - unsigned int width = 0,height = 0; - if (CompositorController::getScreenResolution(width, height)) - mScreenCapture.onScreenCapture(&data[0], width, height); - - free(data); - needsScreenshot = false; - } - RdkShell::update(); - isRunning = sRunning; - - TaskQueue::Task task; - while(mTaskQueue.pop(task)){ - task(); - } - - gRdkShellMutex.unlock(); - double frameTime = (int)RdkShell::microseconds() - (int)startFrameTime; - if (frameTime < maxSleepTime) - { - int sleepTime = (int)maxSleepTime-(int)frameTime; - usleep(sleepTime); - } - } - }); - - service->Register(mClientsMonitor); - char* thunderAccessValue = getenv("THUNDER_ACCESS_VALUE"); - if (NULL != thunderAccessValue) - { - gThunderAccessValue = thunderAccessValue; - } - loadStartupConfig(); - invokeStartupThunderApis(); - char* willDestroyWaitTimeValue = getenv("RDKSHELL_WILLDESTROY_EVENT_WAITTIME"); - if (NULL != willDestroyWaitTimeValue) - { - gWillDestroyEventWaitTime = atoi(willDestroyWaitTimeValue); - } - - m_timer.setInterval(RECONNECTION_TIME_IN_MILLISECONDS); - m_timer.start(); - std::cout << "Started SystemServices connection timer" << std::endl; - char* rdkshelltype = getenv("RDKSHELL_COMPOSITOR_TYPE"); - if((rdkshelltype != NULL) && (strcmp(rdkshelltype , "surface") == 0)) - { - updateSurfaceClientIdentifiers(mCurrentService); - } -#ifdef ENABLE_RIALTO_FEATURE - LOGWARN("Creating rialto connector"); - RialtoConnector *rialtoBridge = new RialtoConnector(); - rialtoConnector = std::shared_ptr(rialtoBridge); -#endif // ENABLE_RIALTO_FEATURE - sem_wait(&gInitializeSemaphore); - return ""; - } - - void RDKShell::loadStartupConfig() - { -#ifdef RFC_ENABLED - const char* startupConfigFileName = getenv("RDKSHELL_STARTUP_CONFIG"); - if (startupConfigFileName) - { - std::ifstream startupConfigFile; - try - { - startupConfigFile.open(startupConfigFileName, std::ifstream::binary); - } - catch (...) - { - std::cout << "RDKShell startup config file read error : [unable to open/read file (" << startupConfigFileName << ")]\n"; - return; - } - std::stringstream strStream; - strStream << startupConfigFile.rdbuf(); - JsonObject startupConfigData; - try - { - startupConfigData = strStream.str(); - } - catch(...) - { - std::cout << "RDKShell startup config file read error : [json format is incorrect (" << startupConfigFileName << ")]\n"; - startupConfigFile.close(); - return; - } - startupConfigFile.close(); - - if (startupConfigData.HasLabel("rdkshellStartup") && (startupConfigData["rdkshellStartup"].Content() == JsonValue::type::ARRAY)) - { - const JsonArray& jsonValue = startupConfigData["rdkshellStartup"].Array(); - - for (int k = 0; k < jsonValue.Length(); k++) - { - std::string name(""); - std::string actionJson(""); - - if (!(jsonValue[k].Content() == JsonValue::type::OBJECT)) - { - std::cout << "one of rdkshell startup config entry is of wrong format" << std::endl; - continue; - } - const JsonObject& configEntry = jsonValue[k].Object(); - - //check for entry validity - if (!(configEntry.HasLabel("RFC") && configEntry.HasLabel("thunderApi"))) - { - std::cout << "one of rdkshell startup config entry is of wrong format or not having RFC/thunderApi parameter" << std::endl; - continue; - } - - //populate rfc entry - const JsonValue& rfcValue = configEntry["RFC"]; - if (!(rfcValue.Content() == JsonValue::type::STRING)) - { - std::cout << "rfc type is non-string type and so ignoring entry" << std::endl; - continue; - } - std::string rfc = rfcValue.String(); - - //populate thunder api entry - const JsonValue& thunderApiValue = configEntry["thunderApi"]; - if (!(thunderApiValue.Content() == JsonValue::type::STRING)) - { - std::cout << "thunder api type is non-string type and so ignoring entry" << std::endl; - continue; - } - std::string thunderApi = thunderApiValue.String(); - - //populate params - JsonObject params; - if (configEntry.HasLabel("params")) - { - const JsonValue& paramsValue = configEntry["params"]; - if (!(paramsValue.Content() == JsonValue::type::OBJECT)) - { - std::cout << "one of rdkshell config entry has non-object type params" << std::endl; - continue; - } - params = paramsValue.Object(); - } - RDKShellStartupConfig config; - config.rfc = rfc; - config.thunderApi = thunderApi; - config.params = params; - gStartupConfigs.push_back(config); - } - } - else - { - std::cout << "Ignored file read due to rdkshellStartup entry is not present"; - } - } - else - { - std::cout << "Ignored file read due to rdkshell staup config environment variable not set\n"; - } -#else - std::cout << "rfc is not enabled and not loading startup configs " << std::endl; -#endif - } - - void RDKShell::invokeStartupThunderApis() - { -#ifdef RFC_ENABLED - for (std::vector::iterator iter = gStartupConfigs.begin() ; iter != gStartupConfigs.end(); iter++) - { - std::string rfc = iter->rfc; - std::string thunderApi = iter->thunderApi; - JsonObject& apiParams = iter->params; - - RFC_ParamData_t rfcParam; - bool ret = Utils::getRFCConfig((char*)rfc.c_str(), rfcParam); - if (true == ret && (strncasecmp(rfcParam.value,"true",4) == 0)) - { - std::cout << "invoking thunder api " << thunderApi << std::endl; - uint32_t status = 0; - JsonObject joResult; - status = getThunderControllerClient()->Invoke(RDKSHELL_THUNDER_TIMEOUT, thunderApi.c_str(), apiParams, joResult); - if (status > 0) - { - std::cout << "invoking thunder api " << thunderApi << " failed - " << status << std::endl; - } - } - else - { - std::cout << "rfc " << rfc << " not enabled " << std::endl; - } - } -#else - std::cout << "rfc is not enabled and not invoking thunder apis " << std::endl; -#endif - gStartupConfigs.clear(); - } - - void RDKShell::Deinitialize(PluginHost::IShell* service) - { - LOGINFO("Deinitialize"); - gRdkShellMutex.lock(); - RdkShell::deinitialize(); - sRunning = false; - gRdkShellMutex.unlock(); - shellThread.join(); - std::vector clientList; - CompositorController::getClients(clientList); - std::vector::iterator ptr; - for(ptr=clientList.begin();ptr!=clientList.end();ptr++) - { - RdkShell::CompositorController::removeListener((*ptr),mEventListener); - } - mCurrentService = nullptr; - service->Unregister(mClientsMonitor); - mClientsMonitor->Release(); - RDKShell::_instance = nullptr; - mRemoteShell = false; - CompositorController::setEventListener(nullptr); - mEventListener = nullptr; - mEnableUserInactivityNotification = false; - gActivePluginsData.clear(); - gRdkShellMutex.lock(); - for (unsigned int i=0; imSemaphore); - gCreateDisplayRequests[i] = nullptr;//cid - } - } - gCreateDisplayRequests.clear(); - for (unsigned int i=0; imSemaphore); - gKillClientRequests[i] = nullptr;//cid - } - } - gKillClientRequests.clear(); - gRdkShellMutex.unlock(); - gExternalDestroyApplications.clear(); - sem_destroy(&gInitializeSemaphore); - } - - string RDKShell::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - - std::shared_ptr > RDKShell::getThunderControllerClient(std::string callsign, std::string localidentifier) - { - string query = "token=" + sThunderSecurityToken; - Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), (_T(gThunderAccessValue))); - std::shared_ptr > thunderClient = make_shared >(callsign.c_str(), localidentifier.c_str(), false, query); - return thunderClient; - } - - std::shared_ptr> RDKShell::getPackagerPlugin() - { - string query = "token=" + sThunderSecurityToken; - Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), (_T(gThunderAccessValue))); - return make_shared>("Packager.1", "", false, query); - } - - std::shared_ptr> RDKShell::getOCIContainerPlugin() - { - string query = "token=" + sThunderSecurityToken; - Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), (_T(gThunderAccessValue))); - return make_shared>("org.rdk.OCIContainer.1", "", false, query); - } - - void RDKShell::pluginEventHandler(const JsonObject& parameters) - { - std::string message; - parameters.ToString(message); - if (parameters.HasLabel("powerState")) - { - std::string powerState = parameters["powerState"].String(); - std::string prevState = parameters["currentPowerState"].String(); - std::cout << "powerState and PrevState inside pluginEventHandler " << prevState << "to" << powerState << std::endl; - if ((powerState.compare("STANDBY") == 0) || (powerState.compare("LIGHT_SLEEP") == 0) || (powerState.compare("DEEP_SLEEP") == 0)) - { - std::cout << "Received power state change to sleep " << std::endl; - JsonObject request, response; - request["visible"] = false; - getThunderControllerClient("org.rdk.RDKShell.1")->Invoke(0, "launchResidentApp", request, response); - } - - if ((prevState == "STANDBY" || prevState == "LIGHT_SLEEP" || prevState == "DEEP_SLEEP" || prevState == "OFF") - && powerState == "ON") - { - std::cout << "received power state change to ON" << std::endl; - JsonObject request, response; - request["callsign"] = "ResidentApp"; - request["visible"] = true; - getThunderControllerClient("org.rdk.RDKShell.1")->Invoke(0, "setVisibility", request, response); - gRdkShellMutex.lock(); - CompositorController::getLastKeyPress(mLastWakeupKeyCode, mLastWakeupKeyModifiers, mLastWakeupKeyTimestamp); - gRdkShellMutex.unlock(); - } - } - } - - void RDKShell::RdkShellListener::onApplicationLaunched(const std::string& client) - { - std::cout << "RDKShell onApplicationLaunched event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_LAUNCHED, params); - } - - void RDKShell::RdkShellListener::onApplicationConnected(const std::string& client) - { - std::cout << "RDKShell onApplicationConnected event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_CONNECTED, params); - } - - void RDKShell::RdkShellListener::onApplicationDisconnected(const std::string& client) - { - std::cout << "RDKShell onApplicationDisconnected event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_DISCONNECTED, params); - } - - void RDKShell::RdkShellListener::onApplicationTerminated(const std::string& client) - { - std::cout << "RDKShell onApplicationTerminated event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_TERMINATED, params); - } - - void RDKShell::RdkShellListener::onApplicationFirstFrame(const std::string& client) - { - std::cout << "RDKShell onApplicationFirstFrame event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_FIRST_FRAME, params); - } - - void RDKShell::RdkShellListener::onApplicationSuspended(const std::string& client) - { - std::cout << "RDKShell onApplicationSuspended event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_SUSPENDED, params); - } - - void RDKShell::RdkShellListener::onApplicationResumed(const std::string& client) - { - std::cout << "RDKShell onApplicationResumed event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_RESUMED, params); - } - - void RDKShell::RdkShellListener::onApplicationActivated(const std::string& client) - { - std::cout << "RDKShell onApplicationActivated event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_ACTIVATED, params); - } - - void RDKShell::RdkShellListener::onApplicationFocusChanged(const std::string& client) - { - std::cout << "RDKShell onApplicationFocused event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_ON_APP_FOCUSCHANGED, params); - } - - void RDKShell::RdkShellListener::onUserInactive(const double minutes) - { - std::cout << "RDKShell onUserInactive event received ..." << minutes << std::endl; - JsonObject params; - params["minutes"] = std::to_string(minutes); - mShell.notify(RDKSHELL_EVENT_ON_USER_INACTIVITY, params); - } - - void RDKShell::RdkShellListener::onDeviceLowRamWarning(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb) - { - std::cout << "RDKShell onDeviceLowRamWarning event received ..." << "free memory - " << freeKb << ", available memory - " << availableKb << ", swap used - " << usedSwapKb << std::endl; - JsonObject params; - params["ram"] = freeKb; - params["availablememory"] = availableKb; - params["usedswap"] = usedSwapKb; - mShell.notify(RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING, params); - } - - void RDKShell::RdkShellListener::onDeviceCriticallyLowRamWarning(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb) - { - std::cout << "RDKShell onDeviceCriticallyLowRamWarning event received ..." << "free memory - " << freeKb << ", available memory - " << availableKb << ", swap used - " << usedSwapKb << std::endl; - JsonObject params; - params["ram"] = freeKb; - params["availablememory"] = availableKb; - params["usedswap"] = usedSwapKb; - mShell.notify(RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING, params); - } - - void RDKShell::RdkShellListener::onDeviceLowRamWarningCleared(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb) - { - std::cout << "RDKShell onDeviceLowRamWarningCleared event received ..." << "free memory - " << freeKb << ", available memory - " << availableKb << ", swap used - " << usedSwapKb << std::endl; - JsonObject params; - params["ram"] = freeKb; - params["availablememory"] = availableKb; - params["usedswap"] = usedSwapKb; - mShell.notify(RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING_CLEARED, params); - } - - void RDKShell::RdkShellListener::onDeviceCriticallyLowRamWarningCleared(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb) - { - std::cout << "RDKShell onDeviceCriticallyLowRamWarningCleared event received ..." << "free memory - " << freeKb << ", available memory - " << availableKb << ", swap used - " << usedSwapKb << std::endl; - JsonObject params; - params["ram"] = freeKb; - params["availablememory"] = availableKb; - params["usedswap"] = usedSwapKb; - mShell.notify(RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING_CLEARED, params); - } - - void RDKShell::RdkShellListener::onEasterEgg(const std::string& name, const std::string& actionJson) - { - std::cout << "RDKShell onEasterEgg event received ..." << name << std::endl; - if (false == mShell.mEnableEasterEggs) - { - std::cout << "easter eggs disabled and not processing event" << std::endl; - return; - } - - if (actionJson.length() == 0) - { - JsonObject params; - params["name"] = name; - mShell.notify(RDKSHELL_EVENT_ON_EASTER_EGG, params); - } - else - { - try - { - JsonObject actionObject = JsonObject(actionJson.c_str()); - - std::cout << "RDKShell onEasterEgg event actionJsonstring .. " << actionJson.c_str() << std::endl; - if (actionObject.HasLabel("invoke")) - { - std::string invoke = actionObject["invoke"].String(); - size_t lastPositionOfDot = invoke.find_last_of("."); - auto thunderController = getThunderControllerClient(); - bool isRDKShellPluginRequest = false; - if (lastPositionOfDot != std::string::npos) - { - std::string callsign = invoke.substr(0, lastPositionOfDot); - std::cout << "callsign will be " << callsign << std::endl; - if (callsign.compare("org.rdk.RDKShell.1") != 0) - { - activate(mShell.mCurrentService, callsign); - } - else - { - isRDKShellPluginRequest = true; - } - } - - std::cout << "invoking method " << invoke.c_str() << std::endl; - JsonObject joResult; - if (isRDKShellPluginRequest) - { - RDKShellApiRequest apiRequest; - apiRequest.mName = invoke.substr(19); - apiRequest.mRequest = actionObject.HasLabel("params")?actionObject["params"].Object():JsonObject(); - mShell.launchRequestThread(apiRequest); - } - else - { - uint32_t status = 0; - if (actionObject.HasLabel("params")) - { - // setting wait Time to 2 seconds - gRdkShellMutex.unlock(); - status = thunderController->Invoke(RDKSHELL_THUNDER_TIMEOUT, invoke.c_str(), actionObject["params"].Object(), joResult); - gRdkShellMutex.lock(); - } - else - { - JsonObject joParams; - joParams["params"] = JsonObject(); - // setting wait Time to 2 seconds - gRdkShellMutex.unlock(); - status = thunderController->Invoke(RDKSHELL_THUNDER_TIMEOUT, invoke.c_str(), joParams, joResult); - gRdkShellMutex.lock(); - } - if (status > 0) - { - std::cout << "failed to invoke " << invoke << "on easter egg. status: " << status << std::endl; - } - } - } - else if(actionObject.HasLabel("initData")){ - JsonObject setparams; - JsonObject initDataSize; - JsonObject invokeobject; - JsonObject nameobject; - JsonObject namespacekey; - JsonObject namespaceValue; - std::string callsign; - std::string namespaceval; - std::string key; - std::string KeyValue; - std::string CallsignValue; - std::string value; - std::string initDataSizevalue; - JsonObject Params; - std::cout << "RDKShell onEasterEgg event to process initData...\n"; - - JsonArray initData = actionObject["initData"].Array(); - - initDataSize = initData[0].Object(); - int initDataSizeCount = 0; - if (initDataSize.HasLabel("initDataSize")){ - initDataSizeCount = initDataSize["initDataSize"].Number(); - } - for (int setVal = 1; setVal < initDataSizeCount;setVal++) { - setparams = initData[setVal].Object(); - if (setparams.HasLabel("invoke")){ - callsign = setparams["invoke"].String(); - } - if (setparams.HasLabel("params")){ - Params = setparams["params"].Object(); - } - - if (Params.HasLabel("namespace")) { - namespaceval = Params["namespace"].String(); - } - if (Params.HasLabel("key")) { - key = Params["key"].String(); - } - if (Params.HasLabel("value")) { - KeyValue = Params["value"].String(); - } - std::cout << "RDKShell onEasterEgg calling setValue." << namespaceval << key<< KeyValue << std::endl; - setValue(mShell.mCurrentService, namespaceval, key, KeyValue); - } - JsonObject RDklaunch = initData[initDataSizeCount].Object(); - - if (RDklaunch.HasLabel("invoke")) { - CallsignValue = RDklaunch["invoke"].String(); - } - std::cout << "RDKShell onEasterEgg event to process KeyValue .." << CallsignValue << std::endl; - auto thunderController1 = getThunderControllerClient(); - - - std::cout << "invoking method " << CallsignValue.c_str() << std::endl; - JsonObject joResult; - std::cout << " before filling apiRequest \n"; - RDKShellApiRequest apiRequest; - apiRequest.mName = CallsignValue.substr(19); - apiRequest.mRequest = RDklaunch.HasLabel("params")?RDklaunch["params"].Object():JsonObject(); - mShell.launchRequestThread(apiRequest); - } - } - catch(...) - { - std::cout << "error in parsing action for easter egg " << std::endl; - } - } - } - - void RDKShell::RdkShellListener::onPowerKey() - { - static double lastPowerKeyTime = 0; - double currentTime = RdkShell::seconds(); - double powerKeyTime = currentTime - lastPowerKeyTime; - if (powerKeyTime < RDKSHELL_POWER_TIME_WAIT) - { - std::cout << "power key pressed too fast, ignoring " << powerKeyTime << std::endl; - } - JsonObject joGetParams; - JsonObject joGetResult; - joGetParams["params"] = JsonObject(); - std::string getPowerStateInvoke = "org.rdk.System.1.getPowerState"; - auto thunderController = getThunderControllerClient(); - uint32_t status = thunderController->Invoke(5000, getPowerStateInvoke.c_str(), joGetParams, joGetResult); - - std::cout << "get power state status: " << status << std::endl; - - if (status > 0) - { - std::cout << "error getting the power state\n"; - lastPowerKeyTime = RdkShell::seconds(); - return; - } - - if (!joGetResult.HasLabel("powerState")) - { - std::cout << "the power state was not returned\n"; - lastPowerKeyTime = RdkShell::seconds(); - return; - } - - const std::string currentPowerState = joGetResult["powerState"].String(); - std::cout << "the current power state is " << currentPowerState << std::endl; - std::string newPowerState = "ON"; - if (currentPowerState == "ON") - { - newPowerState = "STANDBY"; - } - - JsonObject joSetParams; - JsonObject joSetResult; - joSetParams.Set("powerState",newPowerState.c_str()); - joSetParams.Set("standbyReason","power button pressed"); - std::string setPowerStateInvoke = "org.rdk.System.1.setPowerState"; - - std::cout << "attempting to set the power state to " << newPowerState << std::endl; - status = thunderController->Invoke(5000, setPowerStateInvoke.c_str(), joSetParams, joSetResult); - std::cout << "get power state status second: " << status << std::endl; - if (status > 0) - { - std::cout << "error setting the power state\n"; - } - lastPowerKeyTime = RdkShell::seconds(); - } - - void RDKShell::RdkShellListener::onSizeChangeComplete(const std::string& client) - { - std::cout << "RDKShell onSizeChangeComplete event received ..." << client << std::endl; - JsonObject params; - params["client"] = client; - mShell.notify(RDKSHELL_EVENT_SIZE_CHANGE_COMPLETE, params); - } - - // Registered methods (wrappers) begin - uint32_t RDKShell::moveToFrontWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = moveToFront(client); - if (false == result) { - response["message"] = "failed to move front"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::moveToBackWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = moveToBack(client); - if (false == result) { - response["message"] = "failed to move back"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::moveBehindWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("target")) - { - result = false; - response["message"] = "please specify target"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - const string target = parameters["target"].String(); - result = moveBehind(client, target); - if (false == result) { - response["message"] = "failed to move behind"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::setFocusWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = setFocus(client); - if (false == result) { - response["message"] = "failed to set focus"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getFocusedWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - string client = ""; - result = getFocused(client); - if (result & !client.empty()) { - response["message"] = "success to get focused app"; - response["client"] = client; - } else { - response["message"] = "success to get focused app"; - } - returnResponse(result); - } - - uint32_t RDKShell::killWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - // Get the client mime type - std::string mimeType; - getMimeType(client, mimeType); - -#ifdef HIBERNATE_SUPPORT_ENABLED - // RDKShell::kill only destroys wayland display - // and hibernated app will not detect missing display. - // Wakeup app by getting its state - WPEFramework::Core::JSON::String stateString; - auto thunderPlugin = getThunderControllerClient(client); - if(thunderPlugin) - { - thunderPlugin->Get(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - } -#endif - - // Kill the display - result = kill(client); - if (!result) - { - response["message"] = "failed to kill client"; - returnResponse(false); - } - - // App was a DAC app, so kill the container if it's still running - if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_DAC_NATIVE) - { - LOGINFO("Killing container"); - - auto ociContainerPlugin = getOCIContainerPlugin(); - if (!ociContainerPlugin) - { - response["message"] = "OCIContainer plugin initialisation failed"; - returnResponse(false); - } - - JsonObject containerInfoResult; - JsonObject stopContainerResult; - JsonObject param; - param["containerId"] = client; - - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "getContainerInfo", param, containerInfoResult); - - // If success is false, the container isn't running so nothing to do - if (containerInfoResult["success"].Boolean()) - { - auto containerInfo = containerInfoResult["info"].Object(); - - // Dobby knows about that container - what's it doing? - if (containerInfo["state"] == "running" || containerInfo["state"] == "starting") - { - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "stopContainer", param, stopContainerResult); - } - else if (containerInfo["state"] == "paused") - { - // Paused, so force stop - param["force"] = true; - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "stopContainer", param, stopContainerResult); - } - else - { - response["message"] = "Container is not in a state that can be stopped"; - returnResponse(false); - } - - if (!stopContainerResult["success"].Boolean()) - { - result = false; - response["message"] = "Failed to stop container"; - } -#ifdef ENABLE_RIALTO_FEATURE - rialtoConnector->deactivateSession(client); - //Should we wait for the state change ? Naaah -#endif //ENABLE_RIALTO_FEATURE - } - } - } - returnResponse(result); - } - - uint32_t RDKShell::addKeyInterceptWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keyCode")) - { - result = false; - response["message"] = "please specify keyCode"; - } - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - //optional param? - const JsonArray modifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - - const uint32_t keyCode = parameters["keyCode"].Number(); - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = addKeyIntercept(keyCode, modifiers, client); - if (false == result) { - response["message"] = "failed to add key intercept"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::addKeyInterceptsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("intercepts")) - { - result = false; - response["message"] = "please specify intercepts"; - } - if (result) - { - const JsonArray intercepts = parameters["intercepts"].Array(); - result = addKeyIntercepts(intercepts); - if (false == result) - { - response["message"] = "failed to add some key intercepts due to missing parameters or wrong format "; - } - } - returnResponse(result); - } - - uint32_t RDKShell::removeKeyInterceptWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keyCode")) - { - result = false; - response["message"] = "please specify keyCode"; - } - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - //optional param? - const JsonArray modifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - - uint32_t keyCode = parameters["keyCode"].Number(); - // check for * parameter - JsonValue keyCodeValue = parameters["keyCode"]; - if (keyCodeValue.Content() == JsonValue::type::STRING) - { - std::string keyCodeStringValue = parameters["keyCode"].String(); - if (keyCodeStringValue.compare("*") == 0) - { - keyCode = 255; - } - } - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = removeKeyIntercept(keyCode, modifiers, client); - if (false == result) { - response["message"] = "failed to remove key intercept"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::addKeyListenersWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keys")) - { - result = false; - response["message"] = "please specify keys"; - } - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - const JsonArray keys = parameters["keys"].Array(); - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = addKeyListeners(client, keys); - if (false == result) { - response["message"] = "failed to add key listeners"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::removeKeyListenersWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keys")) - { - result = false; - response["message"] = "please specify keys"; - } - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - const JsonArray keys = parameters["keys"].Array(); - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - result = removeKeyListeners(client, keys); - if (false == result) { - response["message"] = "failed to remove key listeners"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::addKeyMetadataListenerWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - gRdkShellMutex.lock(); - result = CompositorController::addKeyMetadataListener(client); - gRdkShellMutex.unlock(); - if (false == result) { - response["message"] = "failed to add key metadata listeners"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::removeKeyMetadataListenerWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - lockRdkShellMutex(); - result = CompositorController::removeKeyMetadataListener(client); - gRdkShellMutex.unlock(); - if (false == result) { - response["message"] = "failed to remove key metadata listeners"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::injectKeyWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keyCode")) - { - result = false; - response["message"] = "please specify keyCode"; - } - - if (result) - { - //optional param? - const JsonArray modifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - - const uint32_t keyCode = parameters["keyCode"].Number(); - result = injectKey(keyCode, modifiers); - if (false == result) { - response["message"] = "failed to inject key"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::generateKeyWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keys")) - { - result = false; - response["message"] = "please specify keyInputs"; - } - - if (result) - { - const JsonArray keyInputs = parameters["keys"].Array(); - - string client = parameters.HasLabel("client") ? parameters["client"].String() : ""; - if (client.empty()) - { - client = parameters.HasLabel("callsign") ? parameters["callsign"].String() : ""; - } - result = generateKey(client, keyInputs); - - if (false == result) { - response["message"] = "failed to generate keys"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getScreenResolutionWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - - bool result = true; - if (!getScreenResolution(response)) - { - response["message"] = "failed to get screen resolution"; - result = false; - } - returnResponse(result); - } - - uint32_t RDKShell::setScreenResolutionWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("w")) - { - result = false; - response["message"] = "please specify w"; - } - if (!parameters.HasLabel("h")) - { - result = false; - response["message"] = "please specify h"; - } - if (result) - { - const unsigned int w = parameters["w"].Number(); - const unsigned int h = parameters["h"].Number(); - - result = setScreenResolution(w, h); - // Just realized: we need one more string& param for the the error message in case setScreenResolution() fails internally - // Also, we might not need a "non-wrapper" method at all, nothing prevents us from implementing it right here - if (false == result) { - response["message"] = "failed to set screen resolution"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::createDisplayWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - string displayName(""); - if (parameters.HasLabel("displayName")) - { - displayName = parameters["displayName"].String(); - } - uint32_t displayWidth = 0; - if (parameters.HasLabel("displayWidth")) - { - displayWidth = parameters["displayWidth"].Number(); - } - uint32_t displayHeight = 0; - if (parameters.HasLabel("displayHeight")) - { - displayHeight = parameters["displayHeight"].Number(); - } - - bool virtualDisplay = false; - if (parameters.HasLabel("virtualDisplay")) - { - virtualDisplay = parameters["virtualDisplay"].Boolean(); - } - - uint32_t virtualWidth = 0; - if (parameters.HasLabel("virtualWidth")) - { - virtualWidth = parameters["virtualWidth"].Number(); - } - uint32_t virtualHeight = 0; - if (parameters.HasLabel("virtualHeight")) - { - virtualHeight = parameters["virtualHeight"].Number(); - } - - bool topmost = false; - if (parameters.HasLabel("topmost")) - { - topmost = parameters["topmost"].Boolean(); - } - bool focus = false; - if (parameters.HasLabel("focus")) - { - focus = parameters["focus"].Boolean(); - } - - result = createDisplay(client, displayName, displayWidth, displayHeight, - virtualDisplay, virtualWidth, virtualHeight, topmost, focus); - if (false == result) { - response["message"] = "failed to create display"; - } - else - { -#ifdef ENABLE_RIALTO_FEATURE - if (parameters.HasLabel("rialtoSocket")) - { - string rialtoSocket = parameters["rialtoSocket"].String(); - - if (rialtoConnector->initialized() == false) - { - LOGWARN("Initializing rialto connector...."); - rialtoConnector->initialize(); - } - - LOGWARN("Creating app session ...."); - if (rialtoConnector->createAppSession(client, displayName, rialtoSocket) == false) - { - response["message"] = "Rialto app session initialisation failed"; - result = false; - } - else if (rialtoConnector->waitForStateChange(client, RialtoServerStates::ACTIVE, RIALTO_TIMEOUT_MILLIS) == false) - { - response["message"] = "Rialto app session not ready."; - result = false; - } - } -#endif //ENABLE_RIALTO_FEATURE - } - } - returnResponse(result); - } - - uint32_t RDKShell::getClientsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - bool result = true; - JsonArray clients; - if (!getClients(clients)) - { - response["message"] = "failed to get clients"; - result = false; - } else { - response["clients"] = clients; - result = true; - } - returnResponse(result); - } - - uint32_t RDKShell::getZOrderWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - bool result = true; - JsonArray clients; - if (!getZOrder(clients)) - { - response["message"] = "failed to get clients"; - result = false; - } else { - response["clients"] = clients; - result = true; - } - returnResponse(result); - } - - uint32_t RDKShell::getBoundsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) { - JsonObject bounds; - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (!getBounds(client, bounds)) - { - response["message"] = "failed to get bounds"; - result = false; - } else { - response["bounds"] = bounds; - result = true; - } - } - returnResponse(result); - } - - uint32_t RDKShell::setBoundsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - unsigned int x=0,y=0,w=0,h=0; - lockRdkShellMutex(); - CompositorController::getBounds(client, x, y, w, h); - gRdkShellMutex.unlock(); - if (parameters.HasLabel("x")) - { - x = parameters["x"].Number(); - } - if (parameters.HasLabel("y")) - { - y = parameters["y"].Number(); - } - if (parameters.HasLabel("w")) - { - w = parameters["w"].Number(); - } - if (parameters.HasLabel("h")) - { - h = parameters["h"].Number(); - } - - result = setBounds(client, x, y, w, h); - if (false == result) { - response["message"] = "failed to set bounds"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getVisibilityWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - bool visible; - result = getVisibility(client, visible); - if (false == result) { - response["message"] = "failed to get visibility"; - } - else { - response["visible"] = visible; - } - } - returnResponse(result); - } - - uint32_t RDKShell::setVisibilityWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("visible")) - { - result = false; - response["message"] = "please specify visibility (visible = true/false)"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - const bool visible = parameters["visible"].Boolean(); - - result = setVisibility(client, visible); - // Just realized: we need one more string& param for the the error message in case setScreenResolution() fails internally - // Also, we might not need a "non-wrapper" method at all, nothing prevents us from implementing it right here - - if (false == result) { - response["message"] = "failed to set visibility"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getOpacityWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - unsigned int opacity; - if (!getOpacity(client, opacity)) - { - response["message"] = "failed to get opacity"; - result = false; - } else { - response["opacity"] = opacity; - result = true; - } - } - - returnResponse(result); - } - - uint32_t RDKShell::setOpacityWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("opacity")) - { - result = false; - response["message"] = "please specify opacity"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - const unsigned int opacity = parameters["opacity"].Number(); - - result = setOpacity(client, opacity); - if (false == result) { - response["message"] = "failed to set opacity"; - } - // handle the result - } - returnResponse(result); - } - - uint32_t RDKShell::getScaleWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - double scaleX = 1.0; - double scaleY = 1.0; - if (!getScale(client, scaleX, scaleY)) - { - response["message"] = "failed to get scale"; - result = false; - } else { - response["sx"] = std::to_string(scaleX); - response["sy"] = std::to_string(scaleY); - result = true; - } - } - - returnResponse(result); - } - - uint32_t RDKShell::setScaleWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("sx") && !parameters.HasLabel("sy")) - { - result = false; - response["message"] = "please specify sx and/or sy"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - double scaleX = 1.0; - double scaleY = 1.0; - getScale(client, scaleX, scaleY); - bool decodeSuccess = true; - try - { - if (parameters.HasLabel("sx")) - { - scaleX = std::stod(parameters["sx"].String()); - } - if (parameters.HasLabel("sy")) - { - scaleY = std::stod(parameters["sy"].String()); - } - } - catch(...) - { - decodeSuccess = false; - std::cout << "error decoding sx or sy " << std::endl; - } - if (false == decodeSuccess) - { - response["message"] = "failed to set scale due to invalid parameters"; - result = false; - } - else - { - result = setScale(client, scaleX, scaleY); - if (false == result) { - response["message"] = "failed to set scale"; - } - } - } - returnResponse(result); - } - - uint32_t RDKShell::getHolePunchWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - bool holePunch = true; - result = getHolePunch(client, holePunch); - if (false == result) { - response["message"] = "failed to get hole punch"; - } - else { - response["holePunch"] = holePunch; - } - } - returnResponse(result); - } - - uint32_t RDKShell::setHolePunchWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("holePunch")) - { - result = false; - response["message"] = "please specify hole punch (holePunch = true/false)"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - const bool holePunch = parameters["holePunch"].Boolean(); - - result = setHolePunch(client, holePunch); - - if (false == result) { - response["message"] = "failed to set hole punch"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getLogLevelWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - std::string logLevel = "INFO"; - lockRdkShellMutex(); - result = CompositorController::getLogLevel(logLevel); - gRdkShellMutex.unlock(); - if (false == result) { - response["message"] = "failed to get log level"; - } - else { - response["logLevel"] = logLevel; - } - returnResponse(result); - } - - uint32_t RDKShell::setLogLevelWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("logLevel")) - { - result = false; - response["message"] = "please specify log level (logLevel = DEBUG/INFO/WARN/ERROR/FATAL)"; - } - if (result) - { - std::string logLevel = parameters["logLevel"].String(); - std::string currentLogLevel = "INFO"; - lockRdkShellMutex(); - result = CompositorController::setLogLevel(logLevel); - CompositorController::getLogLevel(currentLogLevel); - gRdkShellMutex.unlock(); - if (false == result) { - response["message"] = "failed to set log level"; - } - else - { - response["logLevel"] = currentLogLevel; - } - } - returnResponse(result); - } - - uint32_t RDKShell::showSplashLogoWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("displayTime")) - { - result = false; - response["message"] = "please specify display time parameter"; - } - if (result) - { - uint32_t displayTime = parameters["displayTime"].Number(); - lockRdkShellMutex(); - gSplashScreenDisplayTime = displayTime; - receivedShowSplashScreenRequest = true; - gRdkShellMutex.unlock(); - } - returnResponse(result); - } - - uint32_t RDKShell::hideSplashLogoWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - LOG_MILESTONE("HIDE_SPLASH_SCREEN"); - bool result = true; - - lockRdkShellMutex(); - result = CompositorController::hideSplashScreen(); - gRdkShellMutex.unlock(); - - returnResponse(result); - } - - uint32_t RDKShell::removeAnimationWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - UNUSED(parameters); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (!removeAnimation(client)) - { - response["message"] = "failed to remove animation"; - result = false; - } - } - returnResponse(result); - } - - uint32_t RDKShell::addAnimationWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (parameters.HasLabel("animations")) - { - const JsonArray animations = parameters["animations"].Array(); - result = addAnimationList(animations); - if (false == result) { - response["message"] = "failed to add animation list"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::enableInactivityReportingWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (false == mEnableUserInactivityNotification) - { - result = false; - response["message"] = "feature is not enabled"; - } - - if (!parameters.HasLabel("enable")) - { - result = false; - response["message"] = "please specify enable parameter"; - } - if (result) - { - const bool enable = parameters["enable"].Boolean(); - - result = enableInactivityReporting(enable); - - if (false == result) { - response["message"] = "failed to set inactivity notification"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::setInactivityIntervalWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (false == mEnableUserInactivityNotification) - { - result = false; - response["message"] = "feature is not enabled"; - } - - if (!parameters.HasLabel("interval")) - { - result = false; - response["message"] = "please specify interval parameter"; - } - if (result) - { - const unsigned int interval = parameters["interval"].Number(); - - result = setInactivityInterval(interval); - // Just realized: we need one more string& param for the the error message in case setScreenResolution() fails internally - // Also, we might not need a "non-wrapper" method at all, nothing prevents us from implementing it right here - - if (false == result) { - response["message"] = "failed to set inactivity interval"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::resetInactivityTimeWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (false == mEnableUserInactivityNotification) - { - result = false; - response["message"] = "feature is not enabled"; - } - if (result) - { - result = resetInactivityTime(); - if (false == result) { - response["message"] = "failed to reset inactivity time"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::scaleToFitWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - unsigned int x = 0, y = 0; - unsigned int clientWidth = 0, clientHeight = 0; - lockRdkShellMutex(); - CompositorController::getBounds(client, x, y, clientWidth, clientHeight); - if (parameters.HasLabel("x")) - { - x = parameters["x"].Number(); - } - if (parameters.HasLabel("y")) - { - y = parameters["y"].Number(); - } - if (parameters.HasLabel("w")) - { - clientWidth = parameters["w"].Number(); - } - if (parameters.HasLabel("h")) - { - clientHeight = parameters["h"].Number(); - } - result = CompositorController::scaleToFit(client, x, y, clientWidth, clientHeight); - gRdkShellMutex.unlock(); - - if (!result) { - response["message"] = "failed to scale to fit"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::launchWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - double launchStartTime = RdkShell::seconds(); - bool result = true; - bool autoDestroy = true; - - if (!parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify callsign"; - } - - string appCallsign(""); - /*if (result) - { - bool launchInProgress = false; - int32_t currentLaunchCount = 0; - gLaunchMutex.lock(); - if (gLaunchCount > 0) - { - launchInProgress = true; - } - else - { - gLaunchCount++; - } - currentLaunchCount = gLaunchCount; - gLaunchMutex.unlock(); - std::cout << "the current launch count is " << currentLaunchCount << std::endl; - if (launchInProgress) - { - const string appCallsign = parameters["callsign"].String(); - std::cout << "launch is in progress. not able to launch another app: " << appCallsign << std::endl; - response["message"] = "failed to launch application. another launch is in progress"; - returnResponse(false); - } - }*/ - if (result) - { - appCallsign = parameters["callsign"].String(); - if (appCallsign.compare("SearchAndDiscovery") == 0) - { - LOG_MILESTONE("PLUI_LAUNCH_START"); - } - bool isApplicationBeingDestroyed = false; - gLaunchDestroyMutex.lock(); - if (gDestroyApplications.find(appCallsign) != gDestroyApplications.end()) - { - isApplicationBeingDestroyed = true; - } - else - { - gLaunchApplications[appCallsign] = true; - } - gLaunchDestroyMutex.unlock(); - if (isApplicationBeingDestroyed) - { - gLaunchMutex.lock(); - gLaunchCount = 0; - gLaunchMutex.unlock(); - response["message"] = "failed to launch application due to active destroy request"; - returnResponse(false); - } - RDKShellLaunchType launchType = RDKShellLaunchType::UNKNOWN; - const string callsign = parameters["callsign"].String(); - const string callsignWithVersion = callsign + ".1"; - string type; - if (parameters.HasLabel("type")) - { - type = parameters["type"].String(); - } - string version = "0.0"; - string uri; - int32_t x = 0; - int32_t y = 0; - uint32_t width = 0; - uint32_t height = 0; - bool suspend = false; - bool visible = true; - bool focused = true; - bool blockAV = false; - string configuration; - string behind; - - // Ensure cloned plugin displays are in a sub-dir based on - // plugin classname - string displayName; - if (type.empty()) - { - displayName = "wst-" + callsign; - } - else - { - string xdgDir; - Core::SystemInfo::GetEnvironment(_T("XDG_RUNTIME_DIR"), xdgDir); - string displaySubdir = xdgDir + "/" + type; - Core::Directory(displaySubdir.c_str()).CreatePath(); - - // don't add XDG_RUNTIME_DIR to display name - displayName = type + "/" + "wst-" + callsign; - } - - if (gRdkShellSurfaceModeEnabled) - { - displayName = "rdkshell_display"; - } - bool scaleToFit = false; - bool setSuspendResumeStateOnLaunch = true; - bool holePunch = true; - bool topmost = false; - bool focus = false; - - if (parameters.HasLabel("type")) - { - type = parameters["type"].String(); - } - if (parameters.HasLabel("version")) - { - version = parameters["version"].String(); - } - if (parameters.HasLabel("uri")) - { - uri = parameters["uri"].String(); - } - if (parameters.HasLabel("configuration")) - { - configuration = parameters["configuration"].String(); - } - if (parameters.HasLabel("behind")) - { - behind = parameters["behind"].String(); - } - if (parameters.HasLabel("displayName")) - { - displayName = parameters["displayName"].String(); - } - if (parameters.HasLabel("suspend")) - { - suspend = parameters["suspend"].Boolean(); - } - if (parameters.HasLabel("visible")) - { - visible = parameters["visible"].Boolean(); - } - if (parameters.HasLabel("focused")) - { - focused = parameters["focused"].Boolean(); - } - if (parameters.HasLabel("scaleToFit")) - { - scaleToFit = parameters["scaleToFit"].Boolean(); - } - if (parameters.HasLabel("w")) - { - width = parameters["w"].Number(); - } - if (parameters.HasLabel("h")) - { - height = parameters["h"].Number(); - } - if (parameters.HasLabel("holePunch")) - { - holePunch = parameters["holePunch"].Boolean(); - } - if (parameters.HasLabel("topmost")) - { - topmost = parameters["topmost"].Boolean(); - } - if (parameters.HasLabel("focus")) - { - focus = parameters["focus"].Boolean(); - } - if (parameters.HasLabel("autodestroy")) - { - autoDestroy = parameters["autodestroy"].Boolean(); - } - if (parameters.HasLabel("blockAV")) - { - blockAV = parameters["blockAV"].Boolean(); - if (true == mErmEnabled) - { - setAVBlocked(callsign, blockAV); - } - } -#ifdef HIBERNATE_SUPPORT_ENABLED - //Reset app suspended/hibernated for launch - gSuspendedOrHibernatedApplicationsMutex.lock(); - auto suspendedOrHibernatedIt = gSuspendedOrHibernatedApplications.find(appCallsign); - if (suspendedOrHibernatedIt != gSuspendedOrHibernatedApplications.end()) - { - gSuspendedOrHibernatedApplications.erase(suspendedOrHibernatedIt); - } - gSuspendedOrHibernatedApplicationsMutex.unlock(); -#endif -#ifdef HIBERNATE_NATIVE_APPS_ON_SUSPENDED - gLaunchedToSuspendedMutex.lock(); - if (suspend) - { - gLaunchedToSuspended.insert(appCallsign); - } - else - { - gLaunchedToSuspended.erase(appCallsign); - } - gLaunchedToSuspendedMutex.unlock(); -#endif - - //check to see if plugin already exists - bool newPluginFound = false; - bool originalPluginFound = false; - for (std::map::iterator pluginDataEntry = gActivePluginsData.begin(); pluginDataEntry != gActivePluginsData.end(); pluginDataEntry++) - { - std::string pluginName = pluginDataEntry->first; - if (pluginName == callsign) - { - newPluginFound = true; - break; - } - else if (pluginName == type) - { - originalPluginFound = true; - } - } - if ((false == newPluginFound) && (false == originalPluginFound)) { - PluginHost::IShell::state state; - if (getServiceState(mCurrentService, callsign, state) == Core::ERROR_NONE) { - newPluginFound = true; - } - if (getServiceState(mCurrentService, type, state) == Core::ERROR_NONE) { - originalPluginFound = true; - } - } - if (!newPluginFound && !originalPluginFound) - { - response["message"] = "failed to launch application. type not found"; - gLaunchMutex.lock(); - gLaunchCount = 0; - gLaunchMutex.unlock(); - gLaunchDestroyMutex.lock(); - gLaunchApplications.erase(appCallsign); - gLaunchDestroyMutex.unlock(); - std::cout << "new launch count loc1: 0\n"; - returnResponse(false); - } - else if (!newPluginFound) - { - std::cout << "attempting to clone type: " << type << " into " << callsign << std::endl; - uint32_t status = cloneService(mCurrentService, type, callsign); - - std::cout << "clone status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = cloneService(mCurrentService, type, callsign); - std::cout << "clone status: " << status << std::endl; - } - - launchType = RDKShellLaunchType::CREATE; - { - bool lockAcquired = false; - double startTime = RdkShell::milliseconds(); - while (!lockAcquired && (RdkShell::milliseconds() - startTime) < RDKSHELL_TRY_LOCK_WAIT_TIME_IN_MS) - { - lockAcquired = gRdkShellMutex.try_lock(); - } - if (!lockAcquired) - { - std::cout << "unable to get lock for create display, defaulting to normal lock\n"; - gRdkShellMutex.lock(); - } - else - { - std::cout << "lock was acquired via try for create display\n"; - } - } - gRdkShellMutex.unlock(); - if (!isClientExists(callsign)) - { - std::shared_ptr request = std::make_shared(callsign, displayName, width, height); - request->mAutoDestroy = autoDestroy; - lockRdkShellMutex(); - gPluginDisplayNameMap[callsign] = displayName; - std::cout << "Added displayname : "<mSemaphore); - } - } - - string configString; - - uint32_t status = 0; - status = getConfig(mCurrentService, callsign, configString); - - std::cout << "config status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = getConfig(mCurrentService, callsign, configString); - std::cout << "config status: " << status << std::endl; - } - - JsonObject configSet; - configSet.FromString(configString); - - if (!configuration.empty()) - { - JsonObject configurationOverrides; - configurationOverrides.FromString(configuration); - JsonObject::Iterator configurationIterator = configurationOverrides.Variants(); - while (configurationIterator.Next()) - { - configSet[configurationIterator.Label()] = configurationIterator.Current(); - } - } - configSet["clientidentifier"] = displayName; - if (!type.empty() && type == "Netflix") - { - std::cout << "setting launchtosuspend for Netflix: " << suspend << std::endl; - configSet["launchtosuspend"] = suspend; - if (!newPluginFound && !suspend) - { - setSuspendResumeStateOnLaunch = false; - } - -#ifdef RFC_ENABLED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Dobby.Netflix.Enable", param)) - { - JsonObject root; - if (strncasecmp(param.value, "true", 4) == 0) - { - std::cout << "dobby rfc true - launching netflix in container mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Container"); - } - else - { - std::cout << "dobby rfc false - launching netflix in local mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Local"); - } - configSet["root"] = root; - } - else - { - std::cout << "reading netflix dobby rfc failed " << std::endl; - } -#else - std::cout << "rfc is disabled and unable to check for netflix container mode " << std::endl; -#endif - } - - if (type == "Cobalt") - { - if (configuration.find("\"preload\"") == std::string::npos) - { - // Enable preload for l2s - bool preload = suspend; - std::cout << "setting Cobalt preload: " << preload << "\n"; - configSet["preload"] = JsonValue(preload); - } - -#ifdef RFC_ENABLED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Dobby.Cobalt.Enable", param)) - { - JsonObject root; - if (strncasecmp(param.value, "true", 4) == 0) - { - std::cout << "dobby rfc true - launching cobalt in container mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Container"); - } - else - { - std::cout << "dobby rfc false - launching cobalt in local mode " << std::endl; - root = configSet["root"].Object(); - root["outofprocess"] = JsonValue(true); - } - configSet["root"] = root; - } - else - { - std::cout << "reading cobalt dobby rfc failed " << std::endl; - } -#else - std::cout << "rfc is disabled and unable to check for cobalt container mode " << std::endl; -#endif - } - - // One RFC controls all WPE-based apps - if (!type.empty() && (type == "HtmlApp" || type == "LightningApp")) - { -#ifdef RFC_ENABLED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Dobby.WPE.Enable", param)) - { - JsonObject root; - if (strncasecmp(param.value, "true", 4) == 0) - { - std::cout << "dobby WPE rfc true - launching " << type << " in container mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Container"); - } - else - { - std::cout << "dobby WPE rfc false - launching " << type << " in out-of-process mode " << std::endl; - root = configSet["root"].Object(); - root["outofprocess"] = JsonValue(true); - } - configSet["root"] = root; - } - else - { - std::cout << "reading dobby WPE rfc failed - launching " << type << " in default mode" << std::endl; - } -#else - std::cout << "rfc is disabled and unable to check for " << type << " container mode " << std::endl; -#endif - } - - if (!type.empty() && type == "SearchAndDiscoveryApp" ) - { -#ifdef RFC_ENABLED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Dobby.SAD.Enable", param)) - { - JsonObject root; - if (strncasecmp(param.value, "true", 4) == 0) - { - std::cout << "dobby SAD rfc true - launching " << type << " in container mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Container"); - } - else - { - std::cout << "dobby SAD rfc false - launching " << type << " in out-of-process mode " << std::endl; - root = configSet["root"].Object(); - root["outofprocess"] = JsonValue(true); - } - configSet["root"] = root; - } - else - { - std::cout << "reading dobby SAD rfc failed - launching " << type << " in default mode" << std::endl; - } -#else - std::cout << "rfc is disabled and unable to check for " << type << " container mode " << std::endl; -#endif - } - - if (!type.empty() && type == "Amazon") - { -#ifdef RFC_ENABLED - RFC_ParamData_t param; - if (Utils::getRFCConfig("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Dobby.Amazon.Enable", param)) - { - JsonObject root; - if (strncasecmp(param.value, "true", 4) == 0) - { - std::cout << "dobby rfc true - launching amazon in container mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Container"); - } - else - { - std::cout << "dobby rfc false - launching amazon in local mode " << std::endl; - root = configSet["root"].Object(); - root["mode"] = JsonValue("Local"); - } - configSet["root"] = root; - } - else - { - std::cout << "reading amazon dobby rfc failed " << std::endl; - } -#else - std::cout << "rfc is disabled and unable to check for amazon container mode " << std::endl; -#endif - } - - string configSetAsString; - configSet.ToString(configSetAsString); - Core::JSON::String configSetAsJsonString; - configSetAsJsonString.FromString(configSetAsString); - status = setConfig(mCurrentService, callsign, configSetAsJsonString.Value()); - - std::cout << "set status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = setConfig(mCurrentService, callsign, configSetAsJsonString.Value()); - std::cout << "set status: " << status << std::endl; - } - - if (launchType == RDKShellLaunchType::UNKNOWN) - { - status = 0; - PluginHost::IShell::state state; - status = getServiceState(mCurrentService, callsign, state); - - std::cout << "get status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = getServiceState(mCurrentService, callsign, state); - std::cout << "get status: " << status << std::endl; - } - - if (status == 0) - { - if (state == PluginHost::IShell::state::DEACTIVATED || - state == PluginHost::IShell::state::DEACTIVATION || - state == PluginHost::IShell::state::PRECONDITION) - { - launchType = RDKShellLaunchType::ACTIVATE; - status = activate(mCurrentService, callsign); - - std::cout << "activate 1 status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = activate(mCurrentService, callsign); - std::cout << "activate 1 status: " << status << std::endl; - } - } - } - else - { - launchType = RDKShellLaunchType::ACTIVATE; - status = activate(mCurrentService, callsign); - std::cout << "activate 2 status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = activate(mCurrentService, callsign); - std::cout << "activate 2 status: " << status << std::endl; - } - } - } - else - { - status = activate(mCurrentService, callsign); - - std::cout << "activate 3 status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = activate(mCurrentService, callsign); - std::cout << "activate 3 status: " << status << std::endl; - } - } - - bool deferLaunch = false; - if (status > 0) - { - result = false; - std::cout << "error activating plugin. status code is " << status << std::endl; - } - else - { - uint32_t tempX = 0; - uint32_t tempY = 0; - uint32_t screenWidth = 0; - uint32_t screenHeight = 0; - { - bool lockAcquired = false; - double startTime = RdkShell::milliseconds(); - while (!lockAcquired && (RdkShell::milliseconds() - startTime) < RDKSHELL_TRY_LOCK_WAIT_TIME_IN_MS) - { - lockAcquired = gRdkShellMutex.try_lock(); - } - if (!lockAcquired) - { - std::cout << "unable to get lock for get bounds, defaulting to normal lock\n"; - gRdkShellMutex.lock(); - } - else - { - std::cout << "lock was acquired via try for get bounds\n"; - } - } - CompositorController::getBounds(callsign, tempX, tempY, screenWidth, screenHeight); - gRdkShellMutex.unlock(); - width = screenWidth; - height = screenHeight; - if (parameters.HasLabel("x")) - { - x = parameters["x"].Number(); - } - if (parameters.HasLabel("y")) - { - y = parameters["y"].Number(); - } - if (parameters.HasLabel("w")) - { - width = parameters["w"].Number(); - } - if (parameters.HasLabel("h")) - { - height = parameters["h"].Number(); - } - { - bool lockAcquired = false; - double startTime = RdkShell::milliseconds(); - while (!lockAcquired && (RdkShell::milliseconds() - startTime) < RDKSHELL_TRY_LOCK_WAIT_TIME_IN_MS) - { - lockAcquired = gRdkShellMutex.try_lock(); - } - if (!lockAcquired) - { - std::cout << "unable to get lock for set bounds, defaulting to normal lock\n"; - gRdkShellMutex.lock(); - } - else - { - std::cout << "lock was acquired via try for set bounds\n"; - } - } - std::cout << "setting the desired bounds\n"; - CompositorController::setBounds(callsign, 0, 0, 1, 1); //forcing a compositor resize flush - CompositorController::setBounds(callsign, x, y, width, height); - gRdkShellMutex.unlock(); - - if (scaleToFit) - { - std::cout << "scaling app to fit full screen" << std::endl; - double sx = 1.0; - double sy = 1.0; - if (width != screenWidth && width !=0) - { - sx = (double)screenWidth / (double)width; - } - if (height != screenHeight && height!=0) - { - sy = (double)screenHeight / (double)height; - } - setScale(callsign, sx, sy); - } - - if (!behind.empty()) - { - //check to ensure behind is a active client - std::cout << "moving " << callsign << " behind " << behind << std::endl; - bool moveBehindResult = moveBehind(callsign, behind); - if (!moveBehindResult) - { - std::cout << "unable to move behind " << behind << std::endl; - } - } - - gPluginDataMutex.lock(); - { - auto notificationIt = gStateNotifications.find(callsign); - if (notificationIt == gStateNotifications.end()) { - PluginHost::IStateControl* stateControl(mCurrentService->QueryInterfaceByCallsign(callsign)); - if (stateControl) { - auto* handler = new Core::Sink(callsign, *this); - stateControl->Register(handler); - stateControl->Release(); - gStateNotifications[callsign] = handler; - } - } else { - notificationIt->second->enableLaunch(true); - deferLaunch = true; - } - } - gPluginDataMutex.unlock(); - - if (setSuspendResumeStateOnLaunch) - { - if (suspend) - { - if (launchType == RDKShellLaunchType::UNKNOWN) - { - gPluginDataMutex.lock(); - std::map::iterator pluginStateChangeEntry = gPluginsEventListener.find(callsign); - if (pluginStateChangeEntry != gPluginsEventListener.end()) - { - PluginStateChangeData* data = pluginStateChangeEntry->second; - data->enableLaunch(true); - deferLaunch = true; - } - gPluginDataMutex.unlock(); - launchType = RDKShellLaunchType::SUSPEND; - } - - WPEFramework::Core::JSON::String stateString; - stateString = "suspended"; - status = JSONRPCDirectLink(mCurrentService, callsign).Set(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - - std::cout << "setting the state to suspended\n"; - visible = false; - } - else - { - if (launchType == RDKShellLaunchType::UNKNOWN) - { - gPluginDataMutex.lock(); - std::map::iterator pluginStateChangeEntry = gPluginsEventListener.find(callsign); - if (pluginStateChangeEntry != gPluginsEventListener.end()) - { - PluginStateChangeData* data = pluginStateChangeEntry->second; - data->enableLaunch(true); - deferLaunch = true; - } - gPluginDataMutex.unlock(); - launchType = RDKShellLaunchType::RESUME; - } - - WPEFramework::Core::JSON::String stateString; - stateString = "resumed"; - status = JSONRPCDirectLink(mCurrentService, callsign).Set(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - - std::cout << "setting the state to resumed\n"; - } - } - - setVisibility(callsign, visible); - setHolePunch(callsign, holePunch); - if (!visible) - { - focused = false; - } - if (focused) - { - std::cout << "setting the focused app to " << callsign << std::endl; - setFocus(callsign); - } - - setTopmost(callsign, topmost, focus); - JsonObject urlResult; - if (!uri.empty()) - { - WPEFramework::Core::JSON::String urlString; - urlString = uri; - status = JSONRPCDirectLink(mCurrentService, callsign).Set(RDKSHELL_THUNDER_TIMEOUT, "url",urlString); - if (status > 0) - { - std::cout << "failed to set url to " << uri << " with status code " << status << std::endl; - } - } - } - - if (status > 0 || !result) - { - result = false; - } - else - { - string launchTypeString; - switch (launchType) - { - case CREATE: - launchTypeString = "create"; - break; - case ACTIVATE: - launchTypeString = "activate"; - break; - case SUSPEND: - launchTypeString = "suspend"; - break; - case RESUME: - launchTypeString = "resume"; - break; - default: - launchTypeString = "unknown"; - break; - } - std::cout << "Application:" << callsign << " took " << (RdkShell::seconds() - launchStartTime)*1000 << " milliseconds to launch " << std::endl; - gLaunchMutex.lock(); - gLaunchCount = 0; - gLaunchMutex.unlock(); - if (setSuspendResumeStateOnLaunch && deferLaunch && ((launchType == SUSPEND) || (launchType == RESUME))) - { - std::cout << "deferring application launch " << std::endl; - } - else - { - onLaunched(callsign, launchTypeString); - } - response["launchType"] = launchTypeString; - } - - } - if (!result) - { - response["message"] = "failed to launch application"; - } - gLaunchMutex.lock(); - gLaunchCount = 0; - gLaunchMutex.unlock(); - gLaunchDestroyMutex.lock(); - gLaunchApplications.erase(appCallsign); - gLaunchDestroyMutex.unlock(); - std::cout << "new launch count at loc2 is 0\n"; - - returnResponse(result); - } - - uint32_t RDKShell::suspendWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify callsign"; - } - if (result) - { - uint32_t status; - const string callsign = parameters["callsign"].String(); - std::cout << "about to suspend " << callsign << std::endl; - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - bool isApplicationBeingDestroyed = false; - gLaunchDestroyMutex.lock(); - if (gDestroyApplications.find(client) != gDestroyApplications.end()) - { - isApplicationBeingDestroyed = true; - } - if (gExternalDestroyApplications.find(client) != gExternalDestroyApplications.end()) - { - isApplicationBeingDestroyed = true; - } - gLaunchDestroyMutex.unlock(); - if (isApplicationBeingDestroyed) - { - std::cout << "ignoring suspend for " << client << " as it is being destroyed " << std::endl; - result=false; - response["message"] = "failed to suspend application"; - returnResponse(result); - } - gDestroyMutex.lock(); - PluginHost::IStateControl* stateControl(mCurrentService->QueryInterfaceByCallsign(callsign)); - if (stateControl) - { - stateControl->Request(PluginHost::IStateControl::SUSPEND); - stateControl->Release(); - gDestroyMutex.unlock(); - status = Core::ERROR_NONE; - } - else - { - gDestroyMutex.unlock(); - WPEFramework::Core::JSON::String stateString; - stateString = "suspended"; - const string callsignWithVersion = callsign + ".1"; - status = getThunderControllerClient(callsignWithVersion)->Set(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - } - if (status > 0) - { - std::cout << "failed to suspend " << callsign << ". status: " << status << std::endl; - result = false; - } - else - { - setVisibility(callsign, false); - onSuspended(callsign); - } - } - if (!result) - { - response["message"] = "failed to suspend application"; - } - returnResponse(result); - } - - uint32_t RDKShell::destroyWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify callsign"; - } - if (result) - { - const string callsign = parameters["callsign"].String(); - setVisibility(callsign, false); - bool isApplicationBeingLaunched = false; - gLaunchDestroyMutex.lock(); - if (gLaunchApplications.find(callsign) != gLaunchApplications.end()) - { - isApplicationBeingLaunched = true; - } - else - { - gDestroyApplications[callsign] = true; - } - gLaunchDestroyMutex.unlock(); - if (isApplicationBeingLaunched) - { - std::cout << "failed to destroy " << callsign << " as launch in progress" << std::endl; - response["message"] = "failed to destroy application as same application being launched"; - returnResponse(false); - } - std::cout << "destroying " << callsign << std::endl; - gDestroyMutex.lock(); - uint32_t status = deactivate(mCurrentService, callsign); - gDestroyMutex.unlock(); - if (status > 0) - { - std::cout << "failed to destroy " << callsign << ". status: " << status << std::endl; - result = false; - } - else - { - if (callsign == "factoryapp") - { - removeFactoryModeEasterEggs(); - sFactoryModeStart = false; - sFactoryAppLaunchStatus = NOTLAUNCHED; - } - onDestroyed(callsign); - } - gLaunchDestroyMutex.lock(); - gDestroyApplications.erase(callsign); - gLaunchDestroyMutex.unlock(); - } - if (!result) - { - response["message"] = "failed to destroy application"; - } - returnResponse(result); - } - - uint32_t RDKShell::launchApplicationWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client")) - { - result = false; - response["message"] = "please specify client"; - } - if (!parameters.HasLabel("uri")) - { - result = false; - response["message"] = "please specify uri"; - } - if (!parameters.HasLabel("mimeType")) - { - result = false; - response["message"] = "please specify mimeType"; - } - if (result) - { - const string client = parameters["client"].String(); - string uri = parameters["uri"].String(); - const string mimeType = parameters["mimeType"].String(); - - if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_DAC_NATIVE) - { - // Starting a DAC app. Get the info from Packager - LOGINFO("Starting DAC app"); - string bundlePath; -#ifdef ENABLE_RIALTO_FEATURE - string appId; -#endif //ENABLE_RIALTO_FEATURE - { - // find the bundle location - JsonObject infoParams; - JsonObject infoResult; - - string id = uri; - string version = "1.0"; - string dactype = "dac"; - // uri can optionally contain version and dactype - // like: id;version;dactype - auto delimiterPos = uri.find(";"); - if (delimiterPos != string::npos) - { - id = uri.substr(0, delimiterPos); - version = uri.substr(delimiterPos + 1); - uri = id; - delimiterPos = version.find(";"); - if (delimiterPos != string::npos) { - dactype = version.substr(delimiterPos + 1); - version = version.substr(0, delimiterPos); - } - } - infoParams.Set("id", id.c_str()); - infoParams.Set("version", version.c_str()); - infoParams.Set("type", dactype.c_str()); - LOGINFO("Querying LISA about dac app: %s %s %s", dactype.c_str(), id.c_str(), version.c_str()); - uint32_t status = JSONRPCDirectLink(mCurrentService, LISA_CALLSIGN).Invoke( - RDKSHELL_THUNDER_TIMEOUT, "getStorageDetails", infoParams, infoResult); - if (status == 0) - { - if (infoResult.HasLabel("apps") && infoResult["apps"].Object().HasLabel("path")) - { - bundlePath = infoResult["apps"].Object()["path"].String(); - } - if (bundlePath.empty()) - { - LOGINFO("LISA reports app is not installed"); - } - } - else - { - LOGINFO("LISA not active"); - } -#ifdef ENABLE_RIALTO_FEATURE - appId = id; -#endif // ENABLE_RIALTO_FEATURE - } - - if (bundlePath.empty()) - { - auto packagerPlugin = getPackagerPlugin(); - if (!packagerPlugin) - { - response["message"] = "Packager initialisation failed"; - returnResponse(false); - } - // See if the app is actually installed - JsonObject installParams; - JsonObject installResult; - - installParams.Set("pkgId", uri.c_str()); - packagerPlugin->Invoke(1000, "isInstalled", installParams, installResult); - - if (!installResult.Get("available").Boolean()) - { - response["message"] = "Packager reports app is not installed"; - returnResponse(false); - } - - // App is installed, find the bundle location - JsonObject infoParams; - JsonObject infoResult; - - infoParams.Set("pkgId", uri.c_str()); - packagerPlugin->Invoke(1000, "getPackageInfo", infoParams, infoResult); - - bundlePath = infoResult["bundlePath"].String(); - } - - // We know where the app lives and are ready to start it, - // create a display with rdkshell - if (!createDisplay(client, "wst-"+uri)) - { - response["message"] = "Could not create display"; - returnResponse(false); - } - - string str_runtimeDir; - char* runtimeDir = getenv("XDG_RUNTIME_DIR"); - if(NULL != runtimeDir) - { - str_runtimeDir = string(runtimeDir); - } - string display = str_runtimeDir + "/" + (gRdkShellSurfaceModeEnabled ? RDKSHELL_SURFACECLIENT_DISPLAYNAME : "wst-"+uri); - - // Set mime type - if (!setMimeType(client, mimeType)) - { - LOGWARN("Failed to set mime type - non fatal..."); - } -#ifdef ENABLE_RIALTO_FEATURE - - if(!rialtoConnector->initialized()) - { - LOGWARN("Initializing rialto connector...."); - rialtoConnector->initialize(); - } - LOGWARN("Creating app session ...."); - if(!rialtoConnector->createAppSession(client,display, appId)) - { - response["message"] = "Rialto app session initialisation failed"; - returnResponse(false); - } - if(!rialtoConnector->waitForStateChange(appId,RialtoServerStates::ACTIVE, RIALTO_TIMEOUT_MILLIS)) - { - response["message"] = "Rialto app session not ready."; - returnResponse(false); - } -#endif //ENABLE_RIALTO_FEATURE - // Start container - auto ociContainerPlugin = getOCIContainerPlugin(); - if (!ociContainerPlugin) - { -#ifdef ENABLE_RIALTO_FEATURE - rialtoConnector->deactivateSession(client); -#endif //ENABLE_RIALTO_FEATURE - response["message"] = "OCIContainer initialisation failed"; - returnResponse(false); - } - - JsonObject ociContainerResult; - JsonObject param; - - // Container ID set to client so we can find the container - // when suspend/resume/killing which use client id - param["containerId"] = client; - param["bundlePath"] = bundlePath; - param["westerosSocket"] = display; - - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "startContainer", param, ociContainerResult); - - if (!ociContainerResult["success"].Boolean()) - { - // Something went wrong starting the container, destory the display we just created - kill(client); -#ifdef ENABLE_RIALTO_FEATURE - rialtoConnector->deactivateSession(client); -#endif //ENABLE_RIALTO_FEATURE - response["message"] = "Could not start Dobby container"; - returnResponse(false); - } - JsonObject params; - params["client"] = client; - notify(RDKSHELL_EVENT_ON_APP_LAUNCHED, params); - } - else if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_NATIVE) - { - bool topmost = false; - bool focus = false; - - if (parameters.HasLabel("topmost")) - { - topmost = parameters["topmost"].Boolean(); - } - if (parameters.HasLabel("focus")) - { - focus = parameters["focus"].Boolean(); - } - - gRdkShellMutex.lock(); - result = CompositorController::launchApplication(client, uri, mimeType, topmost, focus); - RdkShell::CompositorController::addListener(client, mEventListener); - gRdkShellMutex.unlock(); - - if (!result) - { - response["message"] = "failed to launch application"; - } - } - else - { - result = false; - response["message"] = "Unsupported MIME type"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::suspendApplicationWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - const string client = parameters["client"].String(); - - std::string mimeType; - if (!getMimeType(client, mimeType)) - { - response["message"] = "Could not determine app mime type"; - returnResponse(false); - } - - if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_NATIVE) - { - lockRdkShellMutex(); - result = CompositorController::suspendApplication(client); - gRdkShellMutex.unlock(); - } - else if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_DAC_NATIVE) - { - // Pause the container with Dobby - LOGINFO("Pausing DAC app"); - - auto ociContainerPlugin = getOCIContainerPlugin(); - - if (!ociContainerPlugin) - { - response["message"] = "OCIContainer initialisation failed"; - returnResponse(false); - } - - JsonObject ociContainerResult; - JsonObject param; - param["containerId"] = client; - - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "pauseContainer", param, ociContainerResult); - - if (!ociContainerResult["success"].Boolean()) - { - response["message"] = "Could not pause container"; - returnResponse(false); - } -#ifdef ENABLE_RIALTO_FEATURE - rialtoConnector->suspendSession(client); - if(!rialtoConnector->waitForStateChange(client,RialtoServerStates::INACTIVE, RIALTO_TIMEOUT_MILLIS)) - { - response["message"] = "Rialto app session could not be set inactive."; - returnResponse(false); - } -#endif //ENABLE_RIALTO_FEATURE - } - else - { - response["message"] = "Unsupported mime type"; - returnResponse(false); - } - - // Make the application hidden - result = setVisibility(client, false); - if (!result) - { - response["message"] = "failed to suspend application"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::resumeApplicationWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - const string client = parameters["client"].String(); - - std::string mimeType; - if (!getMimeType(client, mimeType)) - { - response["message"] = "Could not determine app mime type"; - returnResponse(false); - } - - if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_NATIVE) - { - lockRdkShellMutex(); - result = CompositorController::resumeApplication(client); - gRdkShellMutex.unlock(); - } - else if (mimeType == RDKSHELL_APPLICATION_MIME_TYPE_DAC_NATIVE) - { - // Resume the container with Dobby - LOGINFO("Resuming DAC app"); - - auto ociContainerPlugin = getOCIContainerPlugin(); - if (!ociContainerPlugin) - { - response["message"] = "OCIContainer initialisation failed"; - returnResponse(false); - } -#ifdef ENABLE_RIALTO_FEATURE - rialtoConnector->resumeSession(client); - if(!rialtoConnector->waitForStateChange(client,RialtoServerStates::ACTIVE,RIALTO_TIMEOUT_MILLIS)) - { - response["message"] = "Rialto app session not ready."; - returnResponse(false); - } -#endif //ENABLE_RIALTO_FEATURE - JsonObject ociContainerResult; - JsonObject param; - - param["containerId"] = client; - ociContainerPlugin->Invoke(RDKSHELL_THUNDER_TIMEOUT, "resumeContainer", param, ociContainerResult); - - if (!ociContainerResult["success"].Boolean()) - { - response["message"] = "Could not resume container"; - returnResponse(false); - } - } - else - { - response["message"] = "Unsupported mime type"; - returnResponse(false); - } - - // Make the application visible - result = setVisibility(client, true); - - if (!result) - { - response["message"] = "failed to resume application"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::getAvailableTypesWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - string method = "status"; - Core::JSON::ArrayType joResult; - auto thunderController = getThunderControllerClient(); - thunderController->Get>(RDKSHELL_THUNDER_TIMEOUT, method.c_str(), joResult); - - JsonArray availableTypes; - for (uint16_t i = 0; i < joResult.Length(); i++) - { - PluginHost::MetaData::Service service = joResult[i]; - std::string configLine; - service.Configuration.ToString(configLine); - if (!configLine.empty()) - { - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string typeName; - service.Callsign.ToString(typeName); - typeName.erase(std::remove(typeName.begin(),typeName.end(),'\"'),typeName.end()); - availableTypes.Add(typeName); - } - } - } - response["types"] = availableTypes; - - returnResponse(result); - } - - uint32_t RDKShell::setTopmostWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client or callsign"; - } - else if (!parameters.HasLabel("topmost")) - { - result = false; - response["message"] = "please specify topmost (topmost = true/false)"; - } - - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - const bool topmost = parameters["topmost"].Boolean(); - bool focus = false; - if (parameters.HasLabel("focus")) - { - focus = parameters["focus"].Boolean(); - } - result = setTopmost(client, topmost, focus); - if (false == result) - { - response["message"] = "failed to set topmost"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::showWatermarkWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - bool displayWatermark = true; - if (parameters.HasLabel("show")) - { - displayWatermark = parameters["show"].Boolean(); - } - result = showWatermark(displayWatermark); - if (!result) - { - response["message"] = "failed to perform show watermark"; - } - returnResponse(result); - } - - uint32_t RDKShell::enableEasterEggsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - bool enable = true; - if (!parameters.HasLabel("enable")) - { - response["message"] = "enable parameter is not present"; - returnResponse(false); - } - enable = parameters["enable"].Boolean(); - mEnableEasterEggs = enable; - returnResponse(result); - } - - uint32_t RDKShell::showFullScreenImageWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("path")) - { - result = false; - response["message"] = "please specify path"; - } - if (result) - { - std::string path = parameters["path"].String(); - result = showFullScreenImage(path); - if (!result) - { - response["message"] = "failed to perform showw fullscreen"; - } - } - returnResponse(result); - } - - uint32_t RDKShell::hideFullScreenImageWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - lockRdkShellMutex(); - result = CompositorController::hideFullScreenImage(); - gRdkShellMutex.unlock(); - - returnResponse(result); - } - - uint32_t RDKShell::getState(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - string method = "status"; - Core::JSON::ArrayType joResult; - auto thunderController = getThunderControllerClient(); - thunderController->Get>(RDKSHELL_THUNDER_TIMEOUT, method.c_str(), joResult); - - JsonArray stateArray; - for (uint16_t i = 0; i < joResult.Length(); i++) - { - PluginHost::MetaData::Service service = joResult[i]; - if (service.JSONState != PluginHost::MetaData::Service::state::DEACTIVATED && - service.JSONState != PluginHost::MetaData::Service::state::DEACTIVATION && - service.JSONState != PluginHost::MetaData::Service::state::PRECONDITION) - { - std::string configLine; - service.Configuration.ToString(configLine); - if (!configLine.empty()) - { - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string callsign; - service.Callsign.ToString(callsign); - callsign.erase(std::remove(callsign.begin(),callsign.end(),'\"'),callsign.end()); - - WPEFramework::Core::JSON::String stateString; - const string callsignWithVersion = callsign + ".1"; - uint32_t stateStatus = 0; - -#ifdef HIBERNATE_SUPPORT_ENABLED - if(service.JSONState != PluginHost::MetaData::Service::state::HIBERNATED) - { -#endif - stateStatus = getThunderControllerClient(callsignWithVersion)->Get(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); -#ifdef HIBERNATE_SUPPORT_ENABLED - } - else - { - stateString = "hibernated"; - } -#endif - - - if (stateStatus == 0) - { - WPEFramework::Core::JSON::String urlString; - uint32_t urlStatus = 1; -#ifdef HIBERNATE_SUPPORT_ENABLED - if(service.JSONState != PluginHost::MetaData::Service::state::HIBERNATED) - { -#endif - urlStatus = getThunderControllerClient(callsignWithVersion)->Get(RDKSHELL_THUNDER_TIMEOUT, "url",urlString); -#ifdef HIBERNATE_SUPPORT_ENABLED - } -#endif - - JsonObject typeObject; - typeObject["callsign"] = callsign; - typeObject["state"] = stateString.Value(); - if (urlStatus == 0) - { - typeObject["uri"] = urlString.Value(); - } - else - { - typeObject["uri"] = ""; - } - gExitReasonMutex.lock(); - if (gApplicationsExitReason.find(callsign) != gApplicationsExitReason.end()) - { - typeObject["lastExitReason"] = (int)gApplicationsExitReason[callsign]; - } - else - { - typeObject["lastExitReason"] = (int)AppLastExitReason::UNDEFINED; - } - gExitReasonMutex.unlock(); - - stateArray.Add(typeObject); - } - } - } - } - } - response["state"] = stateArray; - - returnResponse(result); - } - - uint32_t RDKShell::getSystemMemoryWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - uint32_t freeKb=0, usedSwapKb=0, totalKb=0, availableKb=0; - result = systemMemory(freeKb, totalKb, availableKb, usedSwapKb); - if (!result) { - response["message"] = "failed to get system Ram"; - } - else - { - response["freeRam"] = freeKb; - response["swapRam"] = usedSwapKb; - response["totalRam"] = totalKb; - response["availablememory"] = availableKb; - } - returnResponse(result); - } - - uint32_t RDKShell::getSystemResourceInfoWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - JsonArray memoryInfo; - - string method = "status"; - Core::JSON::ArrayType joResult; - auto thunderController = getThunderControllerClient(); - thunderController->Get>(RDKSHELL_THUNDER_TIMEOUT, method.c_str(), joResult); - - /*std::cout << "DEACTIVATED: " << PluginHost::MetaData::Service::state::DEACTIVATED << std::endl; - std::cout << "DEACTIVATION: " << PluginHost::MetaData::Service::state::DEACTIVATION << std::endl; - std::cout << "ACTIVATED: " << PluginHost::MetaData::Service::state::ACTIVATED << std::endl; - std::cout << "ACTIVATION: " << PluginHost::MetaData::Service::state::ACTIVATION << std::endl; - std::cout << "DESTROYED: " << PluginHost::MetaData::Service::state::DESTROYED << std::endl; - std::cout << "PRECONDITION: " << PluginHost::MetaData::Service::state::PRECONDITION << std::endl; - std::cout << "SUSPENDED: " << PluginHost::MetaData::Service::state::SUSPENDED << std::endl; - std::cout << "RESUMED: " << PluginHost::MetaData::Service::state::RESUMED << std::endl;*/ - - JsonArray stateArray; - for (uint16_t i = 0; i < joResult.Length(); i++) - { - PluginHost::MetaData::Service service = joResult[i]; - if (service.JSONState != PluginHost::MetaData::Service::state::DEACTIVATED && - service.JSONState != PluginHost::MetaData::Service::state::DEACTIVATION && - service.JSONState != PluginHost::MetaData::Service::state::PRECONDITION) - { - std::string configLine; - service.Configuration.ToString(configLine); - if (!configLine.empty()) - { - JsonObject serviceConfig = JsonObject(configLine.c_str()); - if (serviceConfig.HasLabel("clientidentifier")) - { - std::string callsign; - service.Callsign.ToString(callsign); - callsign.erase(std::remove(callsign.begin(),callsign.end(),'\"'),callsign.end()); - - WPEFramework::Core::JSON::String stateString; - const string callsignWithVersion = callsign + ".1"; - uint32_t stateStatus = getThunderControllerClient(callsignWithVersion)->Get(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - - if (stateStatus == 0) - { - result = pluginMemoryUsage(callsign, memoryInfo); - } - } - } - } - } - - response["types"] = memoryInfo; - - returnResponse(result); - } - - uint32_t RDKShell::setMemoryMonitorWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("enable")) - { - result = false; - response["message"] = "please specify enable parameter"; - } - if (result) - { - std::map configuration; - configuration["enable"] = parameters["enable"].Boolean(); - - if (parameters.HasLabel("interval")) - { - configuration["interval"] = std::stod(parameters["interval"].String()); - } - if (parameters.HasLabel("lowRam")) - { - configuration["lowRam"] = std::stod(parameters["lowRam"].String()); - } - if (parameters.HasLabel("criticallyLowRam")) - { - configuration["criticallyLowRam"] = std::stod(parameters["criticallyLowRam"].String()); - } - RdkShell::setMemoryMonitor(configuration); - } - returnResponse(result); - } - - uint32_t RDKShell::launchFactoryAppWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - if (NOTLAUNCHED != sFactoryAppLaunchStatus) - { - std::cout << "factory app is already running, do nothing"; - response["message"] = " factory app already running"; - returnResponse(false); - } - sFactoryAppLaunchStatus = STARTED; - - subscribeForSystemEvent("onSystemPowerStateChanged"); - - if (parameters.HasLabel("startup")) - { - bool startup = parameters["startup"].Boolean(); - if (startup) - { - std::string valueString; - - std::cout << "attempting to check aging flag \n"; - uint32_t status = getValue(mCurrentService, "FactoryTest", "AgingState", valueString); - std::cout << "get status: " << status << std::endl; - - if (status > 0) - { - response["message"] = " unable to check aging flag"; - sFactoryAppLaunchStatus = NOTLAUNCHED; - returnResponse(false); - } - - if (valueString != "true") - { - std::cout << "aging value is " << valueString << std::endl; - response["message"] = " aging is not set for startup"; - sFactoryAppLaunchStatus = NOTLAUNCHED; - returnResponse(false); - } - } - } - - char* factoryAppUrl = getenv("RDKSHELL_FACTORY_APP_URL"); - if (NULL != factoryAppUrl) - { - if (parameters.HasLabel("resetagingtime")) - { - std::cout << "attempting to set aging total time to 0 \n"; - uint32_t agingTotalTimeSetStatus = setValue(mCurrentService, "FactoryTest", "AgingTotalTime", "0"); - std::cout << "aging total time set status: " << agingTotalTimeSetStatus << std::endl; - } - - killAllApps(true); - if (!parameters.HasLabel("nokillresapp")) - { - JsonObject destroyRequest, destroyResponse; - destroyRequest["callsign"] = "ResidentApp"; - destroyWrapper(destroyRequest, destroyResponse); - } - JsonObject launchRequest, configuration; - launchRequest["callsign"] = "factoryapp"; - launchRequest["type"] = "ResidentApp"; - launchRequest["uri"] = std::string(factoryAppUrl); - configuration["uri"] = launchRequest["uri"]; - launchRequest["focused"] = true; - launchRequest["configuration"] = configuration; - std::cout << "launching " << launchRequest["callsign"].String().c_str() << std::endl; - launchWrapper(launchRequest, response); - bool launchFactoryResult = response.HasLabel("success")?response["success"].Boolean():false; - if (true == launchFactoryResult) - { - std::cout << "Launching factory application succeeded " << std::endl; - } - else - { - std::cout << "Launching factory application failed " << std::endl; - response["message"] = " launching factory application failed "; - sFactoryAppLaunchStatus = NOTLAUNCHED; - returnResponse(false); - } - addFactoryModeEasterEggs(); - - std::cout << "attempting to set factory mode flag \n"; - uint32_t setStatus = setValue(mCurrentService, "FactoryTest", "FactoryMode", "true"); - std::cout << "set status: " << setStatus << std::endl; - - std::cout << "attempting to set factory allow exit flag \n"; - uint32_t setExitStatus = setValue(mCurrentService, "FactoryTest", "AllowExit", "true"); - std::cout << "set status: " << setExitStatus << std::endl; - - sFactoryAppLaunchStatus = COMPLETED; - returnResponse(true); - } - else - { - std::cout << "factory app url is empty " << std::endl; - response["message"] = " factory app url is empty"; - sFactoryAppLaunchStatus = NOTLAUNCHED; - returnResponse(false); - } - } - - uint32_t RDKShell::launchFactoryAppShortcutWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - - std::string factoryAppCallsign("factoryapp"); - bool isFactoryAppRunning = false; - std::map::iterator pluginsEntry = gActivePluginsData.find(factoryAppCallsign); - if (pluginsEntry != gActivePluginsData.end()) - { - std::cout << "factory app is running" << std::endl; - isFactoryAppRunning = true; - } - if (isFactoryAppRunning) - { - std::cout << "nothing to do since factory app is running in shortcut check\n"; - returnResponse(true); - } - - std::string valueString; - - std::cout << "attempting to check flag \n"; - uint32_t status = getValue(mCurrentService, "FactoryTest", "ToFacFlag", valueString); - std::cout << "get status: " << status << std::endl; - - if (status > 0) - { - response["message"] = " unable to check toFac flag"; - returnResponse(false); - } - - if (valueString != "M" && valueString != "m") - { - std::cout << "toFac value is " << valueString << std::endl; - response["message"] = " toFac not in the correct mode"; - returnResponse(false); - } - - return launchFactoryAppWrapper(parameters, response); - } - - uint32_t RDKShell::launchResidentAppWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - std::string factoryAppCallsign("factoryapp"); - bool isFactoryAppRunning = false; - gPluginDataMutex.lock(); - std::map::iterator pluginsEntry = gActivePluginsData.find(factoryAppCallsign); - if (pluginsEntry != gActivePluginsData.end()) - { - std::cout << "factory app is already running" << std::endl; - isFactoryAppRunning = true; - } - gPluginDataMutex.unlock(); - if (!isFactoryAppRunning) - { - std::cout << "nothing to do since factory app is not running\n"; - returnResponse(true); - } - else - { - std::string valueString; - - std::cout << "attempting to check aging flag \n"; - uint32_t agingStatus = getValue(mCurrentService, "FactoryTest", "AgingState", valueString); - std::cout << "aging get status: " << agingStatus << std::endl; - - if (agingStatus == 0) - { - std::cout << "aging value is " << valueString << std::endl; - if (valueString == "true") - { - std::cout << "do not exit the factory app\n"; - response["message"] = " aging is true, do not exit the factory app"; - returnResponse(false); - } - } - else - { - std::cout << "aging value is not set\n"; - } - - std::cout << "attempting to check factory exit flag\n"; - uint32_t factoryExitStatus = getValue(mCurrentService, "FactoryTest", "AllowExit", valueString); - std::cout << "factory exit get status: " << factoryExitStatus << std::endl; - - if (factoryExitStatus == 0) - { - std::cout << "exit value is " << valueString << std::endl; - if (valueString == "false") - { - std::cout << "factory exit flag is false. not allowing the exit of the factory app\n"; - response["message"] = "factory exit flag is false"; - returnResponse(false); - } - else - { - std::cout << "factory exit flag is true. allowing the factory app to exit\n"; - } - } - else - { - std::cout << "factory exit flag not found. not allowing the exit of the factory app\n"; - response["message"] = "factory exit flag not found"; - returnResponse(false); - } - } - setVisibility("factoryapp", false); - std::cout << "RDKShell sending onWillDestroyEvent for factoryapp" << std::endl; - JsonObject params; - params["callsign"] = "factoryapp"; - notify(RDKSHELL_EVENT_ON_WILL_DESTROY, params); - sleep(gWillDestroyEventWaitTime); - - killAllApps(); - //try to kill factoryapp once more if kill apps missed killing due to timeout - JsonObject destroyRequest, destroyResponse; - destroyRequest["callsign"] = "factoryapp"; - destroyWrapper(destroyRequest, destroyResponse); - - std::cout << "attempting to stop hdmi input...\n"; - JsonObject joStopHdmiParams; - JsonObject joStopHdmiResult; - std::string stopHdmiInvoke = "org.rdk.HdmiInput.1.stopHdmiInput"; - - std::cout << "attempting to stop hdmi input \n"; - uint32_t stopHdmiStatus = getThunderControllerClient()->Invoke(RDKSHELL_THUNDER_TIMEOUT, stopHdmiInvoke.c_str(), joStopHdmiParams, joStopHdmiResult); - std::cout << "stopHdmiStatus status: " << stopHdmiStatus << std::endl; - - sForceResidentAppLaunch = true; - string configString; - - int32_t status = 0; - status = getConfig(mCurrentService, "ResidentApp", configString); - - std::cout << "config resident app status: " << status << std::endl; - std::string updatedUrl; - if (status > 0) - { - std::cout << "trying resident app config status one more time...\n"; - status = getConfig(mCurrentService, "ResidentApp", configString); - std::cout << "trying resident app config status: " << status << std::endl; - } - else - { - JsonObject configSet; - configSet.FromString(configString); - updatedUrl = configSet["url"].String(); - if (updatedUrl.find("?") != string::npos) - { - updatedUrl.append("&adjustPowerStateAtStartup=false"); - } - else - { - updatedUrl.append("?adjustPowerStateAtStartup=false"); - } - } - - bool ret = true; - std::string callsign("ResidentApp"); - status = activate(mCurrentService, callsign); - std::cout << "activate resident app status: " << status << std::endl; - if (status > 0) - { - std::cout << "trying status one more time...\n"; - status = activate(mCurrentService, callsign); - std::cout << "activate resident app status: " << status << std::endl; - if (status > 0) - { - response["message"] = "resident app launch failed"; - ret = false; - } - else - { - ret = true; - } - } - - if (parameters.HasLabel("visible")) - { - setVisibility("ResidentApp", parameters["visible"].Boolean()); - } - - if (!updatedUrl.empty()) - { - WPEFramework::Core::JSON::String urlString; - urlString = updatedUrl; - status = JSONRPCDirectLink(mCurrentService, "ResidentApp").Set(RDKSHELL_THUNDER_TIMEOUT, "url",urlString); - std::cout << "set url status " << updatedUrl << " " << status << std::endl; - if (status > 0) - { - std::cout << "failed to set url to " << updatedUrl << " with status code " << status << std::endl; - } - } - - std::cout << "attempting to set factory mode flag \n"; - uint32_t setStatus = setValue(mCurrentService, "FactoryTest", "FactoryMode", "false"); - std::cout << "set status: " << setStatus << std::endl; - sForceResidentAppLaunch = false; - returnResponse(ret); - } - - uint32_t RDKShell::toggleFactoryAppWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool ret = true; - std::string callsign("factoryapp"); - bool isFactoryAppRunning = false; - std::map::iterator pluginsEntry = gActivePluginsData.find(callsign); - if (pluginsEntry != gActivePluginsData.end()) - { - std::cout << "factory app is already running" << std::endl; - isFactoryAppRunning = true; - } - if (isFactoryAppRunning) - { - sForceResidentAppLaunch = true; - launchResidentAppWrapper(parameters, response); - sForceResidentAppLaunch = false; - } - else - { - launchFactoryAppWrapper(parameters, response); - } - ret = response.HasLabel("success")?response["success"].Boolean():false; - returnResponse(ret); - } - - void RDKShell::addFactoryModeEasterEggs() - { - RdkShellEasterEggKeyDetails key1(56, 0, 0); - RdkShellEasterEggKeyDetails key2(48, 0, 0); - RdkShellEasterEggKeyDetails key3(56, 0, 0); - RdkShellEasterEggKeyDetails key4(55, 0, 0); - std::vector keyDetails; - keyDetails.push_back(key1); - keyDetails.push_back(key2); - keyDetails.push_back(key3); - keyDetails.push_back(key4); - addEasterEgg(keyDetails, "AGING_MODE_EXIT1", 10, "{\"invoke\":\"org.rdk.RDKShell.1.exitAgingMode\"}"); - - keyDetails.clear(); - RdkShellEasterEggKeyDetails key5(38, 0, 0); - RdkShellEasterEggKeyDetails key6(38, 0, 0); - RdkShellEasterEggKeyDetails key7(40, 0, 0); - RdkShellEasterEggKeyDetails key8(40, 0, 0); - keyDetails.push_back(key5); - keyDetails.push_back(key6); - keyDetails.push_back(key7); - keyDetails.push_back(key8); - addEasterEgg(keyDetails, "AGING_MODE_EXIT2", 10, "{\"invoke\":\"org.rdk.RDKShell.1.exitAgingMode\"}"); - } - - void RDKShell::removeFactoryModeEasterEggs() - { - removeEasterEgg("AGING_MODE_EXIT1"); - removeEasterEgg("AGING_MODE_EXIT2"); - } - - uint32_t RDKShell::exitAgingModeWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool ret = true; - std::string valueString; - - std::cout << "attempting to check aging state flag \n"; - uint32_t status = getValue(mCurrentService, "FactoryTest", "AgingState", valueString); - std::cout << "get status: " << status << std::endl; - - if (status > 0) - { - response["message"] = " unable to check aging flag"; - returnResponse(false); - } - - if (valueString != "true") - { - std::cout << "aging value is " << valueString << std::endl; - response["message"] = " aging value is not true"; - returnResponse(false); - } - - std::cout << "attempting to set check aging state flag to false\n"; - status = setValue(mCurrentService, "FactoryTest", "AgingState", "false"); - std::cout << "set status: " << status << std::endl; - - JsonObject request, res; - launchResidentAppWrapper(request, res); - - returnResponse(ret); - } - - uint32_t RDKShell::getVirtualResolutionWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - uint32_t width = 0; - uint32_t height = 0; - if (!getVirtualResolution(client, width, height)) - { - response["message"] = "failed to get virtual resolution"; - result = false; - } - else - { - response["width"] = width; - response["height"] = height; - result = true; - } - } - - returnResponse(result); - } - - uint32_t RDKShell::enableKeyRepeatsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("enable")) - { - result = false; - response["message"] = "please specify enable parameter"; - } - if (result) - { - bool enable = parameters["enable"].Boolean(); - result = enableKeyRepeats(enable); - } - returnResponse(result); - } - - uint32_t RDKShell::getKeyRepeatsEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = false, enable=false; - result = getKeyRepeatsEnabled(enable); - if (false == result) { - response["message"] = "failed to get key repeats"; - } - else { - response["keyRepeat"] = enable; - } - returnResponse(result); - } - - uint32_t RDKShell::setVirtualResolutionWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - uint32_t width = 0; - uint32_t height = 0; - getVirtualResolution(client, width, height); - - if (parameters.HasLabel("width")) - { - width = parameters["width"].Number(); - } - if (parameters.HasLabel("height")) - { - height = parameters["height"].Number(); - } - - result = setVirtualResolution(client, width, height); - } - - returnResponse(result); - } - - uint32_t RDKShell::enableVirtualDisplayWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - if (!parameters.HasLabel("enable")) - { - response["message"] = "please specify enable parameter"; - result = false; - } - else - { - bool enable = parameters["enable"].Boolean(); - result = enableVirtualDisplay(client, enable); - } - } - - returnResponse(result); - } - - uint32_t RDKShell::getVirtualDisplayEnabledWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - result = false; - response["message"] = "please specify client"; - } - if (result) - { - string client; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - bool enabled = false; - if (!getVirtualDisplayEnabled(client, enabled)) - { - response["message"] = "failed to call getVirtualDisplayEnabled"; - result = false; - } - else - { - response["enabled"] = enabled; - result = true; - } - } - - returnResponse(result); - } - - uint32_t RDKShell::getLastWakeupKeyWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - std::string serviceCallsign = SYSTEM_SERVICE_CALLSIGN; - serviceCallsign.append(".2"); - auto systemServiceConnection = RDKShell::getThunderControllerClient(serviceCallsign); - JsonObject request, result; - uint32_t status = systemServiceConnection->Invoke(RDKSHELL_THUNDER_TIMEOUT, "getWakeupReason", request, result); - if (Core::ERROR_NONE == status && result.HasLabel("wakeupReason")) - { - std::string wakeupreason = result["wakeupReason"].String(); - if(wakeupreason.compare("WAKEUP_REASON_IR") == 0) - { - JsonObject req, res; - uint32_t status = systemServiceConnection->Invoke(RDKSHELL_THUNDER_TIMEOUT, "getLastWakeupKeyCode", req, res); - if (Core::ERROR_NONE == status && res.HasLabel("wakeupKeyCode")) - { - unsigned int key = res["wakeupKeyCode"].Number(); - unsigned long flags = 0; - uint32_t mappedKeyCode = key, mappedFlags = 0; - keyCodeFromWayland(key, flags, mappedKeyCode, mappedFlags); - response["keyCode"] = JsonValue(mappedKeyCode); - response["modifiers"] = JsonValue(mappedFlags); - std::cout << "Got LastWakeupKey, keyCode: " << mappedKeyCode << " modifiers: " << mappedFlags << std::endl; - returnResponse(true); - } - } - else if (wakeupreason.compare("WAKEUP_REASON_RCU_BT") == 0) - { - std::string remoteControlCallsign = REMOTECONTROL_CALLSIGN; - auto remoteControlConnection = RDKShell::getThunderControllerClient(remoteControlCallsign); - int16_t keyCode = KEYCODE_INVALID, retry = 12; - - while( keyCode == KEYCODE_INVALID ) - { - JsonObject req, res, stat; - req.Set("netType",1); - - uint32_t status = remoteControlConnection->Invoke(RDKSHELL_THUNDER_TIMEOUT, "getNetStatus", req, res); - if (Core::ERROR_NONE == status && res.HasLabel("status")) - { - stat = res["status"].Object(); - - if(stat.HasLabel("remoteData")) - { - JsonArray remoteArray = stat["remoteData"].Array(); - for (int k = 0; k < remoteArray.Length(); k++) - { - JsonObject remote = remoteArray[k].Object(); - if (remote.HasLabel("wakeupKeyCode")) - { - keyCode = remote["wakeupKeyCode"].Number(); - std::cout << "wakeupKeyCode-keyCode: " << keyCode << std::endl; - } - else - std::cout << "wakeupKeyCode missing in remoteInfo\n" << std::endl; - } - } - else - std::cout << "remoteData missing in status\n" << std::endl; - } - else - std::cout << "getNetStatus failed\n" << std::endl; - - retry--; - if ( (retry == 0) || (keyCode != KEYCODE_INVALID) ) - break; - usleep(RETRY_INTERVAL_250MS); - } - - if ( keyCode != KEYCODE_INVALID ) - { - unsigned long flags = 0; - uint32_t mappedKeyCode = keyCode, mappedFlags = 0; - keyCodeFromWayland(keyCode, flags, mappedKeyCode, mappedFlags); - response["keyCode"] = JsonValue(mappedKeyCode); - response["modifiers"] = JsonValue(mappedFlags); - std::cout << "Got LastWakeupKey, keyCode: " << mappedKeyCode << " modifiers: " << mappedFlags << std::endl; - returnResponse(true); - } - } - else - std::cout << "wakeup reason is not IR/BT RCU\n" << std::endl; - } - else - std::cout << "wakeup reason not available\n" << std::endl; - - response["message"] = "unable to get wakeup key"; - returnResponse(false); - } - - uint32_t RDKShell::hideAllClientsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - if (!parameters.HasLabel("hide")) - { - response["message"] = "please specify hide parameter"; - returnResponse(false); - } - bool hide = parameters["hide"].Boolean(); - lockRdkShellMutex(); - std::vector clientList; - CompositorController::getClients(clientList); - for (size_t i=0; iGet(RDKSHELL_THUNDER_TIMEOUT, "state", stateString); - if(stateStatus || stateString != "suspended") - { - std::cout << "ignoring hibenrate for " << callsign << " as it is not suspended " << std::endl; - status = false; - response["message"] = "failed to hibernate native application, not suspended"; - returnResponse(status); - } - } - - std::thread requestsThread = - std::thread([=]() - { - if (!waitForHibernateUnblocked(RDKSHELL_THUNDER_TIMEOUT)) - { - std::cout << "Hibernation of " << callsign << " ignored!" << std::endl; - JsonObject eventMsg; - eventMsg["success"] = false; - eventMsg["message"] = "hibernation blocked"; - notify(RDKShell::RDKSHELL_EVENT_ON_HIBERNATED, eventMsg); - return; - } - - auto thunderController = RDKShell::getThunderControllerClient(); - JsonObject request, result, eventMsg; - request["callsign"] = callsign; - request["timeout"] = RDKSHELL_THUNDER_TIMEOUT; - if(parameters.HasLabel("timeout")) - { - request["timeout"] = parameters["timeout"]; - } - if(parameters.HasLabel("procsequence")) - { - request["procsequence"] = parameters["procsequence"]; - } - uint32_t errCode = thunderController->Invoke(RDKSHELL_THUNDER_TIMEOUT, "hibernate", request, result); - if(errCode > 0) - { - eventMsg["success"] = false; - eventMsg["message"] = result; - } - else - { - eventMsg["callsign"] = callsign; - eventMsg["success"] = true; - gSuspendedOrHibernatedApplicationsMutex.lock(); - gSuspendedOrHibernatedApplications[callsign] = true; - gSuspendedOrHibernatedApplicationsMutex.unlock(); - } - notify(RDKShell::RDKSHELL_EVENT_ON_HIBERNATED, eventMsg); - }); - requestsThread.detach(); - status = true; - } - - returnResponse(status); - } - - uint32_t RDKShell::restoreWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool status = false; - if (parameters.HasLabel("callsign")) - { - std::string callsign = parameters["callsign"].String(); - std::thread requestsThread = - std::thread([=]() - { - auto thunderController = RDKShell::getThunderControllerClient(); - JsonObject request, result, eventMsg; - request["callsign"] = callsign; - - uint32_t errCode = thunderController->Invoke(RDKSHELL_THUNDER_TIMEOUT, "activate", request, result); - if(errCode > 0) - { - eventMsg["success"] = false; - eventMsg["message"] = result; - } - else - { - eventMsg["callsign"] = callsign; - eventMsg["success"] = true; - } - notify(RDKShell::RDKSHELL_EVENT_ON_RESTORED, eventMsg); - }); - requestsThread.detach(); - status = true; - } - - returnResponse(status); - } -#endif - - // Registered methods end - - // Events begin - void RDKShell::notify(const std::string& event, const JsonObject& parameters) - { - sendNotify(event.c_str(), parameters); - } - // Events end - - bool RDKShell::checkForBootupFactoryAppLaunch() - { - std::cout << "inside of checkForBootupFactoryAppLaunch\n"; - if (sPersistentStoreFirstActivated) - { - std::string valueString; - - std::cout << "attempting to check aging state \n"; - uint32_t status = getValue(mCurrentService, "FactoryTest", "AgingState", valueString); - std::cout << "get status for aging state: " << status << std::endl; - - if ((status == 0)) - { - std::cout << "aging result: " << valueString << std::endl; - if (valueString == "true") - { - std::cout << "launching factory app as aging state is set " << std::endl; - return true; - } - } - - std::cout << "attempting to check factory mode \n"; - status = getValue(mCurrentService, "FactoryTest", "FactoryMode", valueString); - std::cout << "get status for factory mode: " << status << std::endl; - - if ((status == 0)) - { - std::cout << "factory mode " << valueString << std::endl; - if (valueString == "true") - { - std::cout << "launching factory app as factory mode is set " << std::endl; - return true; - } - } - } - else - { - std::cout << "persistent store not loaded during factory app check\n"; - } - return false; - } - - void RDKShell::killAllApps(bool enableDestroyEvent) - { - JsonObject stateRequest, stateResponse; - getState(stateRequest, stateResponse); - const JsonArray stateList = stateResponse.HasLabel("state")?stateResponse["state"].Array():JsonArray(); - - if (enableDestroyEvent) - { - for (int i=0; i::iterator displayNameItr = gPluginDisplayNameMap.find(callsign); - if (displayNameItr != gPluginDisplayNameMap.end()) - { - std::string clientId(callsign + ',' + displayNameItr->second); - std::cout << "setAVBlocked callsign: " << callsign << " clientIdentifier:<"<blockAV:"< apps; - gRdkShellMutex.lock(); - status = CompositorController::getBlockedAVApplications(apps); - gRdkShellMutex.unlock(); - if (true == status) - { - std::string appCallSign; - for (std::vector::iterator appsItr = apps.begin(); appsItr != apps.end(); appsItr++) - { - appCallSign = *appsItr; - std::string::size_type pos = appCallSign.find(','); - if (pos != std::string::npos) - { - appsList.Add(appCallSign.substr(0, pos)); - } - } - } - - return status; - } - - // Internal methods begin - - bool RDKShell::moveToFront(const string& client) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::moveToFront(client); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::moveToBack(const string& client) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::moveToBack(client); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::moveBehind(const string& client, const string& target) - { - bool ret = false; - lockRdkShellMutex(); - std::vector clientList; - CompositorController::getClients(clientList); - bool targetFound = false; - for (size_t i=0; i activePluginsData; - gPluginDataMutex.lock(); - activePluginsData = gActivePluginsData; - gPluginDataMutex.unlock(); - - if (!previousFocusedClient.empty()) - { - std::map::iterator previousFocusedIterator; - - for (previousFocusedIterator = activePluginsData.begin(); previousFocusedIterator != activePluginsData.end(); previousFocusedIterator++) - { - std::string compositorName = toLower(previousFocusedIterator->first); - if (compositorName == previousFocusedClient) - { -#ifdef HIBERNATE_SUPPORT_ENABLED - // Skip for suspended and hibernated apps, since not needed and may cause unwanted restore from hibernation - bool skipFocus = false; - gSuspendedOrHibernatedApplicationsMutex.lock(); - if (gSuspendedOrHibernatedApplications.find(previousFocusedIterator->first) != gSuspendedOrHibernatedApplications.end()) - { - skipFocus = gSuspendedOrHibernatedApplications[previousFocusedIterator->first]; - } - - // If app is not suspended nor hibernated, the hibernation for app can still be triggered - // while waiting in a call to QueryInterfaceByCallsign() or Focused(). Further execution - // of QueryInterfaceByCallsign() or Focused() may cause unwanted wakeup. - // Make sure all new hibernations are blocked untill setting the focuse to false finished - if (skipFocus == false) - { - setHibernateBlocked(true); - } - - gSuspendedOrHibernatedApplicationsMutex.unlock(); - - if (skipFocus == false) - { -#endif - std::cout << "setting the focus of " << compositorName << " to false " << std::endl; - Exchange::IFocus *focusedCallsign = mCurrentService->QueryInterfaceByCallsign(previousFocusedIterator->first); - if (focusedCallsign != NULL) - { - uint32_t status = focusedCallsign->Focused(false); - std::cout << "result of set focus to false: " << status << std::endl; - focusedCallsign->Release(); - } -#ifdef HIBERNATE_SUPPORT_ENABLED - setHibernateBlocked(false); - } - else - { - std::cout << "setting the focus for " << compositorName << " to false skipped, plugin suspended or hibernated " << std::endl; - } -#endif - break; - } - } - } - - std::map::iterator focusedEntry = activePluginsData.find(client); - if (focusedEntry != activePluginsData.end()) - { - std::cout << "setting the focus of " << client << " to true " << std::endl; - Exchange::IFocus *focusedCallsign = mCurrentService->QueryInterfaceByCallsign(client); - if (focusedCallsign != NULL) - { - uint32_t status = focusedCallsign->Focused(true); - focusedCallsign->Release(); - std::cout << "result of set focus to true: " << status << std::endl; - } - } - } - return ret; - } - - bool RDKShell::getFocused(string& client) - { - bool ret = false; - gRdkShellMutex.lock(); - ret = CompositorController::getFocused(client); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::kill(const string& client) - { - bool ret = false; - lockRdkShellMutex(); - RdkShell::CompositorController::removeListener(client, mEventListener); - std::shared_ptr request = std::make_shared(client); - gKillClientRequests.push_back(request); - gPluginDisplayNameMap.erase(client); - std::cout << "removed displayname : "<mSemaphore); - ret = request->mResult; - return ret; - } - - bool RDKShell::addKeyIntercepts(const JsonArray& intercepts) - { - bool ret = true; - for (int i=0; i properties; - if (keyInfo.HasLabel("activate")) - { - bool activate = keyInfo["activate"].Boolean(); - properties["activate"] = activate; - } - if (keyInfo.HasLabel("propagate")) - { - bool propagate = keyInfo["propagate"].Boolean(); - properties["propagate"] = propagate; - } - - if (keyInfo.HasLabel("keyCode")) - { - result = CompositorController::addKeyListener(client, keyCode, flags, properties); - } - else - { - result = CompositorController::addNativeKeyListener(client, keyCode, flags, properties); - } - } - else - { - std::cout << "ERROR: Neither keyCode nor nativeKeyCode provided" << std::endl; - } - - if (result == false) - { - break; - } - } - gRdkShellMutex.unlock(); - return result; - } - - bool RDKShell::removeKeyListeners(const string& client, const JsonArray& keys) - { - gRdkShellMutex.lock(); - - bool result = true; - - for (int i=0; i promise; - auto promisePtr = std::make_shared>(std::move(promise)); - auto result = promisePtr->get_future(); - - mTaskQueue.push([keyCode, flags, promisePtr](){ - bool status = CompositorController::injectKey(keyCode, flags); - promisePtr->set_value(status); - }); - - return result.get(); - } - - bool RDKShell::generateKey(const string& client, const JsonArray& keyInputs) - { - bool ret = false; - for (int i=0; i clientList; - CompositorController::getClients(clientList); - transform(keyClient.begin(), keyClient.end(), keyClient.begin(), ::tolower); - if (std::find(clientList.begin(), clientList.end(), keyClient) != clientList.end()) - { - targetFound = true; - } - } - if (targetFound || keyClient == "") - { - ret = CompositorController::generateKey(keyClient, keyCode, flags, virtualKey); - } - gRdkShellMutex.unlock(); - } - return ret; - } - - bool RDKShell::getScreenResolution(JsonObject& out) - { - unsigned int width=0,height=0; - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getScreenResolution(width, height); - gRdkShellMutex.unlock(); - if (true == ret) { - out["w"] = width; - out["h"] = height; - return true; - } - return false; - } - - bool RDKShell::setScreenResolution(const unsigned int w, const unsigned int h) - { - lockRdkShellMutex(); - receivedResolutionRequest = true; - resolutionWidth = w; - resolutionHeight = h; - gRdkShellMutex.unlock(); - return true; - } - - bool RDKShell::setMimeType(const string& client, const string& mimeType) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::setMimeType(client, mimeType); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getMimeType(const string& client, string& mimeType) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getMimeType(client, mimeType); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::createDisplay(const string& client, const string& displayName, const uint32_t displayWidth, const uint32_t displayHeight, - const bool virtualDisplay, const uint32_t virtualWidth, const uint32_t virtualHeight, const bool topmost, const bool focus) - { - bool ret = false; - if (!isClientExists(client)) - { - lockRdkShellMutex(); - std::shared_ptr request = std::make_shared(client, displayName, displayWidth, displayHeight, virtualDisplay, virtualWidth, virtualHeight); - gCreateDisplayRequests.push_back(request); - gRdkShellMutex.unlock(); - sem_wait(&request->mSemaphore); - ret = request->mResult; - } - else - { - std::cout << "Client " << client << "already exist " << std::endl; - } - lockRdkShellMutex(); - RdkShell::CompositorController::addListener(client, mEventListener); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getClients(JsonArray& clients) - { - std::vector clientList; - lockRdkShellMutex(); - CompositorController::getClients(clientList); - gRdkShellMutex.unlock(); - for (size_t i=0; i zOrderList; - lockRdkShellMutex(); - CompositorController::getZOrder(zOrderList); - gRdkShellMutex.unlock(); - for (size_t i=0; i activePluginsData; - gPluginDataMutex.lock(); - activePluginsData = gActivePluginsData; - gPluginDataMutex.unlock(); - std::map::iterator pluginsEntry = activePluginsData.find(client); - if (pluginsEntry != activePluginsData.end()) - { - PluginData& pluginData = pluginsEntry->second; - if (pluginData.mClassName.compare("WebKitBrowser") == 0) - { - std::cout << "setting the visiblity of " << client << " to " << visible << std::endl; - uint32_t status = 0; - gLaunchDestroyMutex.lock(); - if (gDestroyApplications.find(client) != gDestroyApplications.end()) - { - isApplicationBeingDestroyed = true; - } - gLaunchDestroyMutex.unlock(); - if (isApplicationBeingDestroyed) - { - std::cout << "ignoring setvisibility for " << client << " as it is being destroyed " << std::endl; - return false; - } - gDestroyMutex.lock(); - Exchange::IWebBrowser *browser = mCurrentService->QueryInterfaceByCallsign(client); - if (browser != NULL) - { - status = browser->Visibility(visible ? Exchange::IWebBrowser::VisibilityType::VISIBLE : Exchange::IWebBrowser::VisibilityType::HIDDEN); - browser->Release(); - } - else - { - status = 1; - } - gDestroyMutex.unlock(); - if (status > 0) - { - std::cout << "failed to set visibility property to browser " << client << " with status code " << status << std::endl; - } - } - } - - return ret; - } - - bool RDKShell::getOpacity(const string& client, unsigned int& opacity) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getOpacity(client, opacity); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setOpacity(const string& client, const unsigned int opacity) - { - bool ret = false; - lockRdkShellMutex(); - std::vector clientList; - CompositorController::getClients(clientList); - bool targetFound = false; - std::string newClient(client); - std::transform(newClient.begin(), newClient.end(), newClient.begin(), ::tolower); - if (std::find(clientList.begin(), clientList.end(), newClient) != clientList.end()) - { - targetFound = true; - } - if (targetFound) - { - ret = CompositorController::setOpacity(newClient, opacity); - } - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getScale(const string& client, double& scaleX, double& scaleY) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getScale(client, scaleX, scaleY); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setScale(const string& client, const double scaleX, const double scaleY) - { - bool ret = false; - lockRdkShellMutex(); - std::vector clientList; - CompositorController::getClients(clientList); - std::string newClient(client); - bool targetFound = false; - transform(newClient.begin(), newClient.end(), newClient.begin(), ::tolower); - if (std::find(clientList.begin(), clientList.end(), newClient) != clientList.end()) - { - targetFound = true; - } - if (targetFound) - { - ret = CompositorController::setScale(newClient, scaleX, scaleY); - } - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getHolePunch(const string& client, bool& holePunch) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getHolePunch(client, holePunch); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setHolePunch(const string& client, const bool holePunch) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::setHolePunch(client, holePunch); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::removeAnimation(const string& client) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::removeAnimation(client); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::addAnimationList(const JsonArray& animations) - { - lockRdkShellMutex(); - for (int i=0; i animationProperties; - if (animationInfo.HasLabel("x")) - { - int32_t x = animationInfo["x"].Number(); - animationProperties["x"] = x; - } - if (animationInfo.HasLabel("y")) - { - int32_t y = animationInfo["y"].Number(); - animationProperties["y"] = y; - } - if (animationInfo.HasLabel("w")) - { - uint32_t width = animationInfo["w"].Number(); - animationProperties["w"] = width; - } - if (animationInfo.HasLabel("h")) - { - uint32_t height = animationInfo["h"].Number(); - animationProperties["h"] = height; - } - if (animationInfo.HasLabel("sx")) - { - double scaleX = std::stod(animationInfo["sx"].String()); - animationProperties["sx"] = scaleX; - } - if (animationInfo.HasLabel("sy")) - { - double scaleY = std::stod(animationInfo["sy"].String()); - animationProperties["sy"] = scaleY; - } - if (animationInfo.HasLabel("a")) - { - uint32_t opacity = animationInfo["a"].Number(); - animationProperties["a"] = opacity; - } - if (animationInfo.HasLabel("tween")) - { - std::string tween = animationInfo["tween"].String(); - animationProperties["tween"] = tween; - } - if (animationInfo.HasLabel("delay")) - { - try - { - double duration = std::stod(animationInfo["delay"].String()); - animationProperties["delay"] = duration; - } - catch (...) - { - std::cout << "RDKShell unable to set delay for animation " << std::endl; - } - } - CompositorController::addAnimation(client, duration, animationProperties); - } - } - gRdkShellMutex.unlock(); - return true; - } - - bool RDKShell::enableInactivityReporting(const bool enable) - { - lockRdkShellMutex(); - CompositorController::enableInactivityReporting(enable); - gRdkShellMutex.unlock(); - return true; - } - - bool RDKShell::setInactivityInterval(const uint32_t interval) - { - lockRdkShellMutex(); - try - { - CompositorController::setInactivityInterval((double)interval); - } - catch (...) - { - std::cout << "RDKShell unable to set inactivity interval " << std::endl; - } - gRdkShellMutex.unlock(); - return true; - } - - bool RDKShell::resetInactivityTime() - { - lockRdkShellMutex(); - try - { - CompositorController::resetInactivityTime(); - std::cout << "RDKShell inactivity time reset" << std::endl; - } - catch (...) - { - std::cout << "RDKShell unable to reset inactivity time " << std::endl; - } - gRdkShellMutex.unlock(); - return true; - } - - void RDKShell::onLaunched(const std::string& client, const string& launchType) - { - std::cout << "RDKShell onLaunched event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - params["launchType"] = launchType; - notify(RDKSHELL_EVENT_ON_LAUNCHED, params); - } - - void RDKShell::onSuspended(const std::string& client) - { - std::cout << "RDKShell onSuspended event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - - notify(RDKSHELL_EVENT_ON_SUSPENDED, params); - } - - void RDKShell::onDestroyed(const std::string& client) - { - std::cout << "RDKShell onDestroyed event received for " << client << std::endl; - JsonObject params; - params["client"] = client; - notify(RDKSHELL_EVENT_ON_DESTROYED, params); - } - - bool RDKShell::systemMemory(uint32_t &freeKb, uint32_t & totalKb, uint32_t & availableKb, uint32_t & usedSwapKb) - { - lockRdkShellMutex(); - bool ret = RdkShell::systemRam(freeKb, totalKb, availableKb, usedSwapKb); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::pluginMemoryUsage(const string callsign, JsonArray& memoryInfo) - { - JsonObject memoryDetails; - Exchange::IMemory* pluginMemoryInterface(mCurrentService->QueryInterfaceByCallsign(callsign.c_str())); - memoryDetails["callsign"] = callsign; - memoryDetails["ram"] = -1; - if (nullptr != pluginMemoryInterface) - { - memoryDetails["ram"] = pluginMemoryInterface->Resident()/1024; - } - else - { - std::cout << "Memory information not available for " << callsign << std::endl; - } - memoryInfo.Add(memoryDetails); - return true; - } - - - bool RDKShell::getKeyRepeatsEnabled(bool& enable) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getKeyRepeatsEnabled(enable); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::enableKeyRepeats(const bool enable) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::enableKeyRepeats(enable); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setTopmost(const string& callsign, const bool topmost, const bool focus) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::setTopmost(callsign, topmost, focus); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getVirtualResolution(const std::string& client, uint32_t &virtualWidth, uint32_t &virtualHeight) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getVirtualResolution(client, virtualWidth, virtualHeight); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setVirtualResolution(const std::string& client, const uint32_t virtualWidth, const uint32_t virtualHeight) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::setVirtualResolution(client, virtualWidth, virtualHeight); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::enableVirtualDisplay(const std::string& client, const bool enable) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::enableVirtualDisplay(client, enable); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getVirtualDisplayEnabled(const std::string& client, bool &enabled) - { - bool ret = false; - lockRdkShellMutex(); - ret = CompositorController::getVirtualDisplayEnabled(client, enabled); - gRdkShellMutex.unlock(); - return ret; - } - - PluginStateChangeData::PluginStateChangeData(std::string callsign, std::shared_ptr> pluginConnection, RDKShell* rdkshell):mCallSign(callsign), mRDKShell(*rdkshell) - { - mPluginConnection = pluginConnection; - mLaunchEnabled = false; - } - - PluginStateChangeData::~PluginStateChangeData() - { - mPluginConnection = nullptr; - } - - void PluginStateChangeData::enableLaunch(bool enable) - { - mLaunchEnabled = enable; - } - - void PluginStateChangeData::resetConnection() - { - mPluginConnection = nullptr; - } - - void PluginStateChangeData::onStateChangeEvent(const JsonObject& params) - { - bool isSuspended = params["suspended"].Boolean(); - if (mLaunchEnabled) - { - JsonObject launchParams; - launchParams["client"] = mCallSign; - launchParams["launchType"] = (isSuspended)?"suspend":"resume"; - mRDKShell.notify(RDKShell::RDKSHELL_EVENT_ON_LAUNCHED, launchParams); - mLaunchEnabled = false; - } - - if (isSuspended) - { - JsonObject suspendedParams; - suspendedParams["client"] = mCallSign; - mRDKShell.notify(RDKShell::RDKSHELL_EVENT_ON_PLUGIN_SUSPENDED, suspendedParams); - } - } - - bool RDKShell::showWatermark(const bool enable) - { - bool ret = true; - lockRdkShellMutex(); - if (enable) - { - receivedShowWatermarkRequest = true; - } - else - { - ret = CompositorController::hideWatermark(); - } - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::showFullScreenImage(std::string& path) - { - bool ret = true; - lockRdkShellMutex(); - fullScreenImagePath = path; - receivedFullScreenImageRequest = true; - gRdkShellMutex.unlock(); - return ret; - } - - void RDKShell::onTimer() - { - if (gSystemServiceEventsSubscribed) - { - if (m_timer.isActive()) { - m_timer.stop(); - std::cout << "Stopped SystemServices connection timer" << std::endl; - } - } - else - { - if (Core::ERROR_NONE == subscribeForSystemEvent("onSystemPowerStateChanged")) - { - m_timer.stop(); - std::cout << "Stopped SystemServices connection timer after subscription" << std::endl; - } - } - } - - int32_t RDKShell::subscribeForSystemEvent(std::string event) - { - int32_t status = Core::ERROR_GENERAL; - - PluginHost::IShell::state state; - if ((getServiceState(mCurrentService, SYSTEM_SERVICE_CALLSIGN, state) == Core::ERROR_NONE) && (state == PluginHost::IShell::state::ACTIVATED)) - { - std::cout << "SystemService is already activated" << std::endl; - - if (nullptr == gSystemServiceConnection) - { - std::string serviceCallsign = SYSTEM_SERVICE_CALLSIGN; - serviceCallsign.append(".2"); - gSystemServiceConnection = RDKShell::getThunderControllerClient(serviceCallsign); - } - } - - if (nullptr != gSystemServiceConnection) - { - if (!gSystemServiceEventsSubscribed) - { - std::string eventName("onSystemPowerStateChanged"); - status = gSystemServiceConnection->Subscribe(RDKSHELL_THUNDER_TIMEOUT, _T(eventName), &RDKShell::pluginEventHandler, this); - - if (Core::ERROR_NONE == status) - { - std::cout << "RDKShell subscribed to onSystemPowerStateChanged event " << std::endl; - gSystemServiceEventsSubscribed = true; - } - else - { - std::cout << "Subscribe for SystemServices event failed with " << status << std::endl; - gSystemServiceConnection.reset(); - } - - } - else - std::cout << "Already Subscribed to SystemServices events" << std::endl; - } - else - std::cout << "No Connection to SystemServices" << std::endl; - - return status; - } - - void RDKShell::enableLogsFlushing(const bool enable) - { - gRdkShellMutex.lock(); - Logger::enableFlushing(enable); - gRdkShellMutex.unlock(); - } - - void RDKShell::getLogsFlushingEnabled(bool &enabled) - { - gRdkShellMutex.lock(); - enabled = Logger::isFlushingEnabled(); - gRdkShellMutex.unlock(); - } - - bool RDKShell::showCursor() - { - gRdkShellMutex.lock(); - bool ret = CompositorController::showCursor(); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::hideCursor() - { - gRdkShellMutex.lock(); - bool ret = CompositorController::hideCursor(); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::setCursorSize(uint32_t width, uint32_t height) - { - gRdkShellMutex.lock(); - bool ret = CompositorController::setCursorSize(width, height); - gRdkShellMutex.unlock(); - return ret; - } - - bool RDKShell::getCursorSize(uint32_t& width, uint32_t& height) - { - gRdkShellMutex.lock(); - bool ret = CompositorController::getCursorSize(width, height); - gRdkShellMutex.unlock(); - return ret; - } - - uint32_t RDKShell::addEasterEggsWrapper(const JsonObject& parameters, JsonObject& response) - { - LOGINFOMETHOD(); - bool result = true; - - if (!parameters.HasLabel("keySequence")) - { - result = false; - response["message"] = "please specify keySequence"; - } - if (!parameters.HasLabel("id")) - { - result = false; - response["message"] = "please specify id"; - } - if (!parameters.HasLabel("duration")) - { - result = false; - response["message"] = "please specify duration"; - } - if (!parameters.HasLabel("api")) - { - result = false; - response["message"] = "please specify api"; - } - if (!result) - { - returnResponse(result); - } - - std::vector keyDetails; - const JsonArray keyInputs = parameters["keySequence"].Array(); - for (int i=0; i easterEggsList; - gRdkShellMutex.lock(); - getEasterEggs(easterEggsList); - gRdkShellMutex.unlock(); - for (size_t i=0; i clientList; - CompositorController::getClients(clientList); - for (size_t i = 0; i < clientList.size(); i++) - { - result = result && CompositorController::enableInputEvents(clientList[i], enable); - } - - break; - } - else - { - result = result && CompositorController::enableInputEvents(clientName, enable); - } - } - gRdkShellMutex.unlock(); - - return result; - } - // Internal methods end - } // namespace Plugin -} // namespace WPEFramework diff --git a/RDKShell/RDKShell.h b/RDKShell/RDKShell.h deleted file mode 100755 index e5b82a4..0000000 --- a/RDKShell/RDKShell.h +++ /dev/null @@ -1,528 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include "Module.h" -#include -#include -#include -#include -#include "tptimer.h" -#ifdef ENABLE_RIALTO_FEATURE -#include "RialtoConnector.h" -#define RIALTO_TIMEOUT_MILLIS 5000 -#endif -namespace WPEFramework { - - namespace Plugin { - - struct RDKShellApiRequest - { - std::string mName; - JsonObject mRequest; - }; - - class RDKShell : public PluginHost::IPlugin, public PluginHost::JSONRPC { - public: - RDKShell(); - virtual ~RDKShell(); - virtual const string Initialize(PluginHost::IShell* service) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override; - - BEGIN_INTERFACE_MAP(RDKShell) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::ICapture, (&mScreenCapture)) - END_INTERFACE_MAP - - public/*members*/: - static RDKShell* _instance; - - public /*constants*/: - static const string SERVICE_NAME; - //methods - static const string RDKSHELL_METHOD_MOVE_TO_FRONT; - static const string RDKSHELL_METHOD_MOVE_TO_BACK; - static const string RDKSHELL_METHOD_MOVE_BEHIND; - static const string RDKSHELL_METHOD_SET_FOCUS; - static const string RDKSHELL_METHOD_GET_FOCUSED; - static const string RDKSHELL_METHOD_KILL; - static const string RDKSHELL_METHOD_ADD_KEY_INTERCEPT; - static const string RDKSHELL_METHOD_ADD_KEY_INTERCEPTS; - static const string RDKSHELL_METHOD_REMOVE_KEY_INTERCEPT; - static const string RDKSHELL_METHOD_ADD_KEY_LISTENER; - static const string RDKSHELL_METHOD_REMOVE_KEY_LISTENER; - static const string RDKSHELL_METHOD_ADD_KEY_METADATA_LISTENER; - static const string RDKSHELL_METHOD_REMOVE_KEY_METADATA_LISTENER; - static const string RDKSHELL_METHOD_INJECT_KEY; - static const string RDKSHELL_METHOD_GENERATE_KEYS; - static const string RDKSHELL_METHOD_GET_SCREEN_RESOLUTION; - static const string RDKSHELL_METHOD_SET_SCREEN_RESOLUTION; - static const string RDKSHELL_METHOD_CREATE_DISPLAY; - static const string RDKSHELL_METHOD_GET_CLIENTS; - static const string RDKSHELL_METHOD_GET_Z_ORDER; - static const string RDKSHELL_METHOD_GET_BOUNDS; - static const string RDKSHELL_METHOD_SET_BOUNDS; - static const string RDKSHELL_METHOD_GET_VISIBILITY; - static const string RDKSHELL_METHOD_SET_VISIBILITY; - static const string RDKSHELL_METHOD_GET_OPACITY; - static const string RDKSHELL_METHOD_SET_OPACITY; - static const string RDKSHELL_METHOD_GET_SCALE; - static const string RDKSHELL_METHOD_SET_SCALE; - static const string RDKSHELL_METHOD_GET_HOLE_PUNCH; - static const string RDKSHELL_METHOD_SET_HOLE_PUNCH; - static const string RDKSHELL_METHOD_GET_LOG_LEVEL; - static const string RDKSHELL_METHOD_SET_LOG_LEVEL; - static const string RDKSHELL_METHOD_SHOW_SPLASH_LOGO; - static const string RDKSHELL_METHOD_HIDE_SPLASH_LOGO; - static const string RDKSHELL_METHOD_ADD_ANIMATION; - static const string RDKSHELL_METHOD_REMOVE_ANIMATION; - static const string RDKSHELL_METHOD_ENABLE_INACTIVITY_REPORTING; - static const string RDKSHELL_METHOD_SET_INACTIVITY_INTERVAL; - static const string RDKSHELL_METHOD_RESET_INACTIVITY_TIME; - static const string RDKSHELL_METHOD_SCALE_TO_FIT; - static const string RDKSHELL_METHOD_LAUNCH; - static const string RDKSHELL_METHOD_LAUNCH_APP; - static const string RDKSHELL_METHOD_SUSPEND; - static const string RDKSHELL_METHOD_SUSPEND_APP; - static const string RDKSHELL_METHOD_RESUME_APP; - static const string RDKSHELL_METHOD_DESTROY; - static const string RDKSHELL_METHOD_GET_AVAILABLE_TYPES; - static const string RDKSHELL_METHOD_GET_STATE; - static const string RDKSHELL_METHOD_GET_SYSTEM_MEMORY; - static const string RDKSHELL_METHOD_GET_SYSTEM_RESOURCE_INFO; - static const string RDKSHELL_METHOD_SET_MEMORY_MONITOR; - static const string RDKSHELL_METHOD_SHOW_WATERMARK; - static const string RDKSHELL_METHOD_SHOW_FULL_SCREEN_IMAGE; - static const string RDKSHELL_METHOD_HIDE_FULL_SCREEN_IMAGE; - static const string RDKSHELL_METHOD_LAUNCH_FACTORY_APP; - static const string RDKSHELL_METHOD_LAUNCH_FACTORY_APP_SHORTCUT; - static const string RDKSHELL_METHOD_LAUNCH_RESIDENT_APP; - static const string RDKSHELL_METHOD_TOGGLE_FACTORY_APP; - static const string RDKSHELL_METHOD_EXIT_AGING_MODE; - static const string RDKSHELL_METHOD_GET_KEYREPEATS_ENABLED; - static const string RDKSHELL_METHOD_ENABLE_KEYREPEATS; - static const string RDKSHELL_METHOD_SET_TOPMOST; - static const string RDKSHELL_METHOD_GET_VIRTUAL_RESOLUTION; - static const string RDKSHELL_METHOD_SET_VIRTUAL_RESOLUTION; - static const string RDKSHELL_METHOD_ENABLE_VIRTUAL_DISPLAY; - static const string RDKSHELL_METHOD_GET_VIRTUAL_DISPLAY_ENABLED; - static const string RDKSHELL_METHOD_GET_LAST_WAKEUP_KEY; - static const string RDKSHELL_METHOD_HIDE_ALL_CLIENTS; - static const string RDKSHELL_METHOD_GET_SCREENSHOT; - static const string RDKSHELL_METHOD_ENABLE_EASTER_EGGS; - static const string RDKSHELL_METHOD_ENABLE_LOGS_FLUSHING; - static const string RDKSHELL_METHOD_GET_LOGS_FLUSHING_ENABLED; - static const string RDKSHELL_METHOD_SHOW_CURSOR; - static const string RDKSHELL_METHOD_HIDE_CURSOR; - static const string RDKSHELL_METHOD_GET_CURSOR_SIZE; - static const string RDKSHELL_METHOD_SET_CURSOR_SIZE; - static const string RDKSHELL_METHOD_IGNORE_KEY_INPUTS; - static const string RDKSHELL_METHOD_ADD_EASTER_EGGS; - static const string RDKSHELL_METHOD_REMOVE_EASTER_EGGS; - static const string RDKSHELL_METHOD_GET_EASTER_EGGS; - static const string RDKSHELL_METHOD_SET_AV_BLOCKED; - static const string RDKSHELL_METHOD_GET_AV_BLOCKED_APPS; - static const string RDKSHELL_METHOD_ENABLE_INPUT_EVENTS; - static const string RDKSHELL_METHOD_KEY_REPEAT_CONFIG; - static const string RDKSHELL_METHOD_GET_GRAPHICS_FRAME_RATE; - static const string RDKSHELL_METHOD_SET_GRAPHICS_FRAME_RATE; -#ifdef HIBERNATE_SUPPORT_ENABLED - static const string RDKSHELL_METHOD_HIBERNATE; - static const string RDKSHELL_METHOD_RESTORE; -#endif - - // events - static const string RDKSHELL_EVENT_ON_USER_INACTIVITY; - static const string RDKSHELL_EVENT_ON_APP_LAUNCHED; - static const string RDKSHELL_EVENT_ON_APP_CONNECTED; - static const string RDKSHELL_EVENT_ON_APP_DISCONNECTED; - static const string RDKSHELL_EVENT_ON_APP_TERMINATED; - static const string RDKSHELL_EVENT_ON_APP_FIRST_FRAME; - static const string RDKSHELL_EVENT_ON_APP_SUSPENDED; - static const string RDKSHELL_EVENT_ON_APP_RESUMED; - static const string RDKSHELL_EVENT_ON_APP_ACTIVATED; - static const string RDKSHELL_EVENT_ON_APP_FOCUSCHANGED; - static const string RDKSHELL_EVENT_ON_LAUNCHED; - static const string RDKSHELL_EVENT_ON_SUSPENDED; - static const string RDKSHELL_EVENT_ON_DESTROYED; - static const string RDKSHELL_EVENT_ON_PLUGIN_SUSPENDED; - static const string RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING; - static const string RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING; - static const string RDKSHELL_EVENT_DEVICE_LOW_RAM_WARNING_CLEARED; - static const string RDKSHELL_EVENT_DEVICE_CRITICALLY_LOW_RAM_WARNING_CLEARED; - static const string RDKSHELL_EVENT_ON_EASTER_EGG; - static const string RDKSHELL_EVENT_ON_WILL_DESTROY; - static const string RDKSHELL_EVENT_ON_SCREENSHOT_COMPLETE; -#ifdef HIBERNATE_SUPPORT_ENABLED - static const string RDKSHELL_EVENT_ON_HIBERNATED; - static const string RDKSHELL_EVENT_ON_RESTORED; -#endif - - void notify(const std::string& event, const JsonObject& parameters); - void pluginEventHandler(const JsonObject& parameters); - void launchRequestThread(RDKShellApiRequest apiRequest); - - private/*registered methods (wrappers)*/: - - //methods ("parameters" here is "params" from the curl request) - uint32_t moveToFrontWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t moveToBackWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t moveBehindWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setFocusWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getFocusedWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t killWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addKeyInterceptWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addKeyInterceptsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t removeKeyInterceptWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addKeyListenersWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t removeKeyListenersWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addKeyMetadataListenerWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t removeKeyMetadataListenerWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t injectKeyWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t generateKeyWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getScreenResolutionWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setScreenResolutionWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t createDisplayWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getClientsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getZOrderWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getBoundsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setBoundsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getVisibilityWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setVisibilityWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getOpacityWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setOpacityWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getScaleWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setScaleWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getHolePunchWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setHolePunchWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getLogLevelWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setLogLevelWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t showSplashLogoWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t hideSplashLogoWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addAnimationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t removeAnimationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableInactivityReportingWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setInactivityIntervalWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t resetInactivityTimeWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t scaleToFitWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t launchWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t suspendWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t destroyWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t launchApplicationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t suspendApplicationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t resumeApplicationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t destroyApplicationWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getAvailableTypesWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getState(const JsonObject& parameters, JsonObject& response); - uint32_t getSystemMemoryWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getSystemResourceInfoWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setMemoryMonitorWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t showWatermarkWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t showFullScreenImageWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t hideFullScreenImageWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t launchFactoryAppWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t launchFactoryAppShortcutWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t launchResidentAppWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t toggleFactoryAppWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t exitAgingModeWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getKeyRepeatsEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableKeyRepeatsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setTopmostWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getVirtualResolutionWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setVirtualResolutionWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableVirtualDisplayWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getVirtualDisplayEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getLastWakeupKeyWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t hideAllClientsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getScreenshotWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableEasterEggsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableLogsFlushingWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getLogsFlushingEnabledWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t showCursorWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t hideCursorWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setCursorSizeWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getCursorSizeWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t ignoreKeyInputsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t addEasterEggsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t removeEasterEggsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getEasterEggsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setAVBlockedWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getBlockedAVApplicationsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t enableInputEventsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t keyRepeatConfigWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getGraphicsFrameRateWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t setGraphicsFrameRateWrapper(const JsonObject& parameters, JsonObject& response); -#ifdef HIBERNATE_SUPPORT_ENABLED - uint32_t hibernateWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t restoreWrapper(const JsonObject& parameters, JsonObject& response); -#endif - - private/*internal methods*/: - RDKShell(const RDKShell&) = delete; - RDKShell& operator=(const RDKShell&) = delete; - - bool moveToFront(const string& client); - bool moveToBack(const string& client); - bool moveBehind(const string& client, const string& target); - bool setFocus(const string& client); - bool getFocused(string& client); - bool kill(const string& client); - bool addKeyIntercept(const uint32_t& keyCode, const JsonArray& modifiers, const string& client); - bool addKeyIntercepts(const JsonArray& intercepts); - bool removeKeyIntercept(const uint32_t& keyCode, const JsonArray& modifiers, const string& client); - bool addKeyListeners(const string& client, const JsonArray& listeners); - bool removeKeyListeners(const string& client, const JsonArray& listeners); - bool addAnyKeyListener(const string& client, const JsonArray& listeners); - bool injectKey(const uint32_t& keyCode, const JsonArray& modifiers); - bool generateKey(const string& client, const JsonArray& keyInputs); - bool getScreenResolution(JsonObject& out); - bool setScreenResolution(const unsigned int w, const unsigned int h); - bool setMimeType(const string& client, const string& mimeType); - bool getMimeType(const string& client, string& mimeType); - bool createDisplay(const string& client, const string& displayName, const uint32_t displayWidth = 0, const uint32_t displayHeight = 0, - const bool virtualDisplay = false, const uint32_t virtualWidth = 0, const uint32_t virtualHeight = 0, - const bool topmost = false, const bool focus = false); - bool getClients(JsonArray& clients); - bool getZOrder(JsonArray& clients); - bool getBounds(const string& client, JsonObject& bounds); - bool setBounds(const string& client, const unsigned int x, const unsigned int y, const unsigned int w, const unsigned int h); - bool getVisibility(const string& client, bool& visibility); - bool setVisibility(const string& client, const bool visible); - bool getOpacity(const string& client, unsigned int& opacity); - bool setOpacity(const string& client, const unsigned int opacity); - bool getScale(const string& client, double& scaleX, double& scaleY); - bool setScale(const string& client, const double scaleX, const double scaleY); - bool getHolePunch(const string& client, bool& holePunch); - bool setHolePunch(const string& client, const bool holePunch); - bool removeAnimation(const string& client); - bool addAnimationList(const JsonArray& animations); - bool enableInactivityReporting(const bool enable); - bool setInactivityInterval(const uint32_t interval); - bool resetInactivityTime(); - void onLaunched(const std::string& client, const string& launchType); - void onSuspended(const std::string& client); - void onDestroyed(const std::string& client); - bool systemMemory(uint32_t &freeKb, uint32_t & totalKb, uint32_t & availableKb, uint32_t & usedSwapKb); - bool pluginMemoryUsage(const string callsign, JsonArray& memoryInfo); - bool showWatermark(const bool enable); - bool showFullScreenImage(std::string& path); - void killAllApps(bool enableDestroyEvent=false); - bool checkForBootupFactoryAppLaunch(); - bool enableKeyRepeats(const bool enable); - bool getKeyRepeatsEnabled(bool& enable); - bool setTopmost(const string& callsign, const bool topmost, const bool focus); - bool getVirtualResolution(const std::string& client, uint32_t &virtualWidth, uint32_t &virtualHeight); - bool setVirtualResolution(const std::string& client, const uint32_t virtualWidth, const uint32_t virtualHeight); - bool enableVirtualDisplay(const std::string& client, const bool enable); - bool getVirtualDisplayEnabled(const std::string& client, bool &enabled); - void loadStartupConfig(); - void invokeStartupThunderApis(); - int32_t subscribeForSystemEvent(std::string event); - void onTimer(); - - void addFactoryModeEasterEggs(); - void removeFactoryModeEasterEggs(); - void enableLogsFlushing(const bool enable); - void getLogsFlushingEnabled(bool &enabled); - - bool showCursor(); - bool hideCursor(); - bool setCursorSize(uint32_t width, uint32_t height); - bool getCursorSize(uint32_t& width, uint32_t& height); - bool setAVBlocked(const string callsign, bool blockAV); - bool getBlockedAVApplications(JsonArray& appsList); - bool enableInputEvents(const JsonArray& clients, bool enable); - - public: - static std::shared_ptr > getThunderControllerClient(std::string callsign="", std::string localidentifier=""); - - private: - static std::shared_ptr > getPackagerPlugin(); - static std::shared_ptr > getOCIContainerPlugin(); - - private/*classes */: - - class RdkShellListener : public RdkShell::RdkShellEventListener { - - public: - RdkShellListener(RDKShell* shell) - : mShell(*shell) - { - } - - ~RdkShellListener() - { - } - - // rdkshell events listeners - virtual void onApplicationLaunched(const std::string& client); - virtual void onApplicationConnected(const std::string& client); - virtual void onApplicationDisconnected(const std::string& client); - virtual void onApplicationTerminated(const std::string& client); - virtual void onApplicationFirstFrame(const std::string& client); - virtual void onApplicationSuspended(const std::string& client); - virtual void onApplicationResumed(const std::string& client); - virtual void onApplicationActivated(const std::string& client); - virtual void onApplicationFocusChanged(const std::string& client); - virtual void onUserInactive(const double minutes); - virtual void onDeviceLowRamWarning(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb); - virtual void onDeviceCriticallyLowRamWarning(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb); - virtual void onDeviceLowRamWarningCleared(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb); - virtual void onDeviceCriticallyLowRamWarningCleared(const int32_t freeKb, const int32_t availableKb, const int32_t usedSwapKb); - virtual void onEasterEgg(const std::string& name, const std::string& actionJson); - virtual void onPowerKey(); - virtual void onSizeChangeComplete(const std::string& client); - - private: - RDKShell& mShell; - }; - - class MonitorClients : public PluginHost::IPlugin::INotification -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR >= 4)) - , public PluginHost::IPlugin::ILifeTime -#endif - { - private: - MonitorClients() = delete; - MonitorClients(const MonitorClients&) = delete; - MonitorClients& operator=(const MonitorClients&) = delete; - - public: - MonitorClients(RDKShell* shell) - : mShell(*shell) - { - } - ~MonitorClients() - { - } - - public: - BEGIN_INTERFACE_MAP(MonitorClients) - INTERFACE_ENTRY(PluginHost::IPlugin::INotification) -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR >= 4)) - INTERFACE_ENTRY(PluginHost::IPlugin::ILifeTime) -#endif - END_INTERFACE_MAP - - private: - virtual void StateChange(PluginHost::IShell* shell); - void handleInitialize(PluginHost::IShell* shell); - void handleActivated(PluginHost::IShell* shell); - void handleDeactivated(PluginHost::IShell* shell); - void handleDeinitialized(PluginHost::IShell* shell); - -#ifdef USE_THUNDER_R4 - virtual void Initialize(const string& callsign, PluginHost::IShell* plugin); - virtual void Activation(const string& name, PluginHost::IShell* plugin); - virtual void Deactivation(const string& name, PluginHost::IShell* plugin); - virtual void Activated(const string& callSign, PluginHost::IShell* plugin); - virtual void Deactivated(const string& callSign, PluginHost::IShell* plugin); - virtual void Deinitialized(const string& callsign, PluginHost::IShell* plugin); - virtual void Unavailable(const string& callSign, PluginHost::IShell* plugin); -#endif /* USE_THUNDER_R4 */ - private: - RDKShell& mShell; - }; - - class ScreenCapture : public Exchange::ICapture { - public: - ScreenCapture(RDKShell *shell) : mShell(shell) { } - ScreenCapture(const ScreenCapture& copy) : mShell(copy.mShell) { } - - BEGIN_INTERFACE_MAP(ScreenCapture) - INTERFACE_ENTRY(Exchange::ICapture) - END_INTERFACE_MAP - - virtual uint32_t AddRef() const override { return 0; } - virtual uint32_t Release() const override { return 0; } - - virtual const TCHAR* Name() const override { return "ScreenCapture"; } - - virtual bool Capture(ICapture::IStore& storer) override; - void onScreenCapture(const unsigned char *data, unsigned int width, unsigned int height); - - private: - ScreenCapture() = delete; - RDKShell* mShell; - std::vectormCaptureStorers; - }; - - class TaskQueue { - public: - using Task = std::function; - public: - TaskQueue() = default; - ~TaskQueue() = default; - TaskQueue(const TaskQueue&) = delete; - TaskQueue& operator=(const TaskQueue&) = delete; - - void push(Task task); - bool pop(Task& outTask); - private: - std::queue mQueue; - std::mutex mMutex; - }; - - private/*members*/: - bool mRemoteShell; - bool mEnableUserInactivityNotification; - MonitorClients* mClientsMonitor; - std::shared_ptr mEventListener; - PluginHost::IShell* mCurrentService; - //std::mutex m_callMutex; - uint32_t mLastWakeupKeyCode; - uint32_t mLastWakeupKeyModifiers; - uint64_t mLastWakeupKeyTimestamp; - TpTimer m_timer; - bool mEnableEasterEggs; - ScreenCapture mScreenCapture; - bool mErmEnabled; - TaskQueue mTaskQueue; -#ifdef ENABLE_RIALTO_FEATURE - std::shared_ptr rialtoConnector; -#endif //ENABLE_RIALTO_FEATURE - }; - - struct PluginData - { - std::string mClassName; - }; - - class PluginStateChangeData - { - public: - PluginStateChangeData(std::string callsign, std::shared_ptr> pluginConnection, RDKShell* rdkshell); - ~PluginStateChangeData(); - void onStateChangeEvent(const JsonObject& params); - void enableLaunch(bool enable); - void resetConnection(); - - private: - std::string mCallSign; - std::shared_ptr> mPluginConnection; - RDKShell& mRDKShell; - bool mLaunchEnabled; - }; - - } // namespace Plugin -} // namespace WPEFramework diff --git a/RDKShell/README.md b/RDKShell/README.md deleted file mode 100755 index 02fe034..0000000 --- a/RDKShell/README.md +++ /dev/null @@ -1,88 +0,0 @@ ------------------ -# RDKShell - -## Versions -`org.rdk.RDKShell.1` - -## Methods: -``` -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.moveToFront", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.moveToBack", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.moveBehind", "params":{ "client": "org.rdk.Netflix", "target": "org.rdk.RDKBrowser2"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.setFocus", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.kill", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.addKeyIntercept", "params":{"keyCode": 10, "modifiers": ["alt", "shift"], "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.removeKeyIntercept", "params":{"keyCode": 10, "modifiers": ["alt", "shift"], "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getScreenResolution", "params":{}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.setScreenResolution", "params":{ "w": 1920, "h": 1080}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getClients", "params":{}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getZOrder", "params":{}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getBounds", "params":{ "client": "org.rdk.RDKBrowser2"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.setBounds", "params":{"client": "org.rdk.RDKBrowser2", "x": 0, "y": 0, "w": 600, "h": 400}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getVisibility", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.setVisibility", "params":{ "client": "org.rdk.Netflix", "visible": true}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.getOpacity", "params":{ "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKShell.1.setOpacity", "params":{ "client": "org.rdk.Netflix", "opacity": 100}}' http://127.0.0.1:9998/jsonrpc -``` - -## Responses -``` -moveToFront: -{"jsonrpc":"2.0", "id":3, "result": {} } - -moveToBack: -{"jsonrpc":"2.0", "id":3, "result": {} } - -moveBehind: -{"jsonrpc":"2.0", "id":3, "result": {} } - -setFocus: -{"jsonrpc":"2.0", "id":3, "result": {} } - -kill: -{"jsonrpc":"2.0", "id":3, "result": {} } - -addKeyIntercept: -{"jsonrpc":"2.0", "id":3, "result": {} } - -removeKeyIntercept: -{"jsonrpc":"2.0", "id":3, "result": {} } - -getScreenResolution: -{"jsonrpc":"2.0", "id":3, "result": {"w": 1920, "h": 1080} } - -setScreenResolution: -{"jsonrpc":"2.0", "id":3, "result": {} } - -getClients: -{"jsonrpc":"2.0", "id":3, "result": { "clients": ["org.rdk.Netflix", "org.rdk.RDKBrowser2"]} } - -getZOrder: -{"jsonrpc":"2.0", "id":3, "result": { "clients": ["org.rdk.Netflix", "org.rdk.RDKBrowser2"]} } - -getBounds: -{"jsonrpc":"2.0", "id":3, "result": { - "x": 0, - "y": 0, - "w": 600, - "h": 400} } -setBounds: -{"jsonrpc":"2.0", "id":3, "result": {} } - -getVisibility: -{"jsonrpc":"2.0", "id":3, "result": {"visible": true} } - -setVisibility: -{"jsonrpc":"2.0", "id":3, "result": {} } - -getOpacity: -{"jsonrpc":"2.0", "id":3, "result": { "opacity" : 100} } - -setOpacity: -{"jsonrpc":"2.0", "id":3, "result": {} } -``` - -## Events -``` -none -``` diff --git a/RDKShell/RialtoConnector.cpp b/RDKShell/RialtoConnector.cpp deleted file mode 100644 index b82c6e0..0000000 --- a/RDKShell/RialtoConnector.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "RialtoConnector.h" - -extern char **environ; - -namespace WPEFramework -{ - namespace - { - std::list getEnvironmentVariables() - { - std::list environmentVariables; - char **envList = environ; - - for(;*envList;envList++) - { - environmentVariables.emplace_back(*envList); - } - return environmentVariables; - } - } //anonymous namespace to contain private function. - - void RialtoConnector::initialize() - { - LOGWARN(" Rialto Bridge version 1.1"); - firebolt::rialto::common::ServerManagerConfig config; - config.sessionServerEnvVars = getEnvironmentVariables(); - m_serverManagerService = create(shared_from_this(), config); - isInitialized = true; - } - bool RialtoConnector::createAppSession(const std::string &callsign, const std::string &displayName, const std::string &appId) - { - LOGINFO("Creating app session with callsign : '%s', display name : '%s', appid : '%s'", callsign.c_str(), displayName.c_str(), appId.c_str()); - - firebolt::rialto::common::AppConfig config = {appId, displayName}; - return m_serverManagerService->initiateApplication(callsign, - RialtoServerStates::ACTIVE, - config); - } - bool RialtoConnector::resumeSession(const std::string &callsign) - { - if (RialtoServerStates::INACTIVE == getCurrentAppState(callsign)) - return m_serverManagerService->changeSessionServerState(callsign, - RialtoServerStates::ACTIVE); - return false; - } - bool RialtoConnector::suspendSession(const std::string &callsign) - { - if (RialtoServerStates::ACTIVE == getCurrentAppState(callsign)) - return m_serverManagerService->changeSessionServerState(callsign, - RialtoServerStates::INACTIVE); - return false; - } - const RialtoServerStates RialtoConnector::getCurrentAppState(const std::string &callsign) - { - auto state = appStateMap.find(callsign); - if (state != appStateMap.end()) - { - // If the state is not inactive, we have a problem. - return state->second; - } - return RialtoServerStates::ERROR; - } - bool RialtoConnector::deactivateSession(const std::string &callsign) - { - LOGINFO("Deactiving app %s", callsign.c_str()); - RialtoServerStates state = getCurrentAppState(callsign); - if (RialtoServerStates::ACTIVE == state || - RialtoServerStates::INACTIVE == state) - return m_serverManagerService->changeSessionServerState(callsign, - RialtoServerStates::NOT_RUNNING); - LOGINFO("Rialto server is not in active or running state. "); - return false; - } - void RialtoConnector::stateChanged(const std::string &appId, - const RialtoServerStates &state) - { - { - std::lock_guard lockguard(m_stateMutex); - appStateMap[appId] = state; - } - LOGINFO("[RialtoConnector::stateChanged] State change announced for %s to %d, isActive ? %d ", appId.c_str(), - static_cast(state), (state == RialtoServerStates::ACTIVE)); - m_stateCond.notify_one(); - } - - // wait until socket is in given state - // return true when state set, false on timeout - bool RialtoConnector::waitForStateChange(const std::string& appId, const RialtoServerStates& state, int timeoutMillis) - { - bool status = false; - std::unique_lock lock(m_stateMutex); - auto startTime = std::chrono::steady_clock::now(); - auto endTime = startTime + std::chrono::milliseconds(timeoutMillis); - - while (std::chrono::steady_clock::now() < endTime) - { - if (appStateMap[appId] == state) - { - status = true; - break; - } - - auto remainingTime = std::chrono::duration_cast(endTime - std::chrono::steady_clock::now()); - if (remainingTime.count() <= 0) - break; - - m_stateCond.wait_for(lock, remainingTime); - } - - return status; - } - -} // namespace WPEFramework diff --git a/RDKShell/RialtoConnector.h b/RDKShell/RialtoConnector.h deleted file mode 100644 index 0b4b82e..0000000 --- a/RDKShell/RialtoConnector.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include "UtilsLogging.h" -#include -#include -#include -#include -#include "rialto/ServerManagerServiceFactory.h" - -namespace WPEFramework -{ - using namespace rialto::servermanager::service; - // Shadowing to keep Rialto contained in this - typedef firebolt::rialto::common::SessionServerState RialtoServerStates; - - class RialtoConnector : public IStateObserver, public std::enable_shared_from_this - { - public: - RialtoConnector() : isInitialized(false) {} - virtual ~RialtoConnector() = default; - void initialize(); - bool initialized() { return isInitialized; } - bool waitForStateChange(const std::string &appid, const RialtoServerStates &state, int timeoutMillis); - bool createAppSession(const std::string &callsign, const std::string &displayName, const std::string &appId); - bool resumeSession(const std::string &callsign); - bool suspendSession(const std::string &callsign); - - bool deactivateSession(const std::string &callsign); - void stateChanged(const std::string &appId, const RialtoServerStates &state) override; - - RialtoConnector(const RialtoConnector &) = delete; // No copying - RialtoConnector &operator=(const RialtoConnector &) = delete; // No assignment - - private: - bool isInitialized; - std::mutex m_stateMutex; - std::condition_variable m_stateCond; - std::unique_ptr m_serverManagerService; - std::map appStateMap; - - const RialtoServerStates getCurrentAppState(const std::string &callsign); - }; -} // namespace WPEFramework diff --git a/RDKWindowManager/CHANGELOG.md b/RDKWindowManager/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/RDKWindowManager/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/RDKWindowManager/CMakeLists.txt b/RDKWindowManager/CMakeLists.txt deleted file mode 100755 index 516b032..0000000 --- a/RDKWindowManager/CMakeLists.txt +++ /dev/null @@ -1,85 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME RDKWindowManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_RDK_WINDOW_MANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_RDK_WINDOW_MANAGER_AUTOSTART false CACHE STRING "Automatically start RDKWindowManager plugin") -set(PLUGIN_RDK_WINDOW_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_RDK_WINDOW_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start RDKWindowManager plugin") - -add_definitions(-DRDK_WINDOW_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DRDK_WINDOW_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DRDK_WINDOW_MANAGER_API_VERSION_NUMBER_PATCH=0) - -set(RDK_WINDOW_MANAGER_IMPLEMENTATION ${PLUGIN_NAME}Implementation) -add_definitions(-DPLUGIN_RDK_WINDOW_MANAGER_IMPLEMENTATION_NAME="${RDK_WINDOW_MANAGER_IMPLEMENTATION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - RDKWindowManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(RDKWindowManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - RDKWindowManagerImplementation.cpp - Module.cpp) - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set(RDK_WINDOW_MANAGER_INCLUDES $ENV{RDK_WINDOW_MANAGER_INCLUDES}) -separate_arguments(RDK_WINDOW_MANAGER_INCLUDES) -include_directories(BEFORE ${RDK_WINDOW_MANAGER_INCLUDES}) - -if (NOT RDK_SERVICES_TEST) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins -lrdkwindowmanager ${PLUGIN_RDK_WINDOW_MANAGER_EXTRA_LIBRARIES}) -else(RDK_SERVICES_TEST) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_RDK_WINDOW_MANAGER_EXTRA_LIBRARIES}) -endif(RDK_SERVICES_TEST) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/RDKWindowManager/Module.cpp b/RDKWindowManager/Module.cpp deleted file mode 100755 index cd6d4d1..0000000 --- a/RDKWindowManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/RDKWindowManager/Module.h b/RDKWindowManager/Module.h deleted file mode 100755 index ff5f972..0000000 --- a/RDKWindowManager/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_RDKWindowManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/RDKWindowManager/RDKWindowManager.conf.in b/RDKWindowManager/RDKWindowManager.conf.in deleted file mode 100644 index 3d0229b..0000000 --- a/RDKWindowManager/RDKWindowManager.conf.in +++ /dev/null @@ -1,11 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.RDKWindowManager" -autostart = "false" -startuporder = "@PLUGIN_RDK_WINDOW_MANAGER_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_RDK_WINDOW_MANAGER_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) diff --git a/RDKWindowManager/RDKWindowManager.config b/RDKWindowManager/RDKWindowManager.config deleted file mode 100644 index 8a22732..0000000 --- a/RDKWindowManager/RDKWindowManager.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart false) -set (preconditions Platform) -set (callsign "org.rdk.RDKWindowManager") - -if(PLUGIN_RDK_WINDOW_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_RDK_WINDOW_MANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_RDK_WINDOW_MANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) \ No newline at end of file diff --git a/RDKWindowManager/RDKWindowManager.cpp b/RDKWindowManager/RDKWindowManager.cpp deleted file mode 100755 index 0c0610d..0000000 --- a/RDKWindowManager/RDKWindowManager.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "RDKWindowManager.h" - -const string WPEFramework::Plugin::RDKWindowManager::SERVICE_NAME = "org.rdk.RDKWindowManager"; - -namespace WPEFramework { - - namespace { - - static Plugin::Metadata metadata( - /* Version (Major, Minor, Patch) */ - RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MAJOR, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MINOR, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_PATCH, - /* Preconditions */ - {}, - /* Terminations */ - {}, - /* Controls */ - {} - ); - } - - namespace Plugin { - - SERVICE_REGISTRATION(RDKWindowManager, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MAJOR, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MINOR, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_PATCH); - - RDKWindowManager* RDKWindowManager::_instance = nullptr; - - RDKWindowManager::RDKWindowManager() - : PluginHost::JSONRPC() - , mCurrentService(nullptr) - , mConnectionId(0) - , mRDKWindowManagerImpl(nullptr) - , mRDKWindowManagerNotification(this) - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager Constructor"))); - RDKWindowManager::_instance = this; - } - - RDKWindowManager::~RDKWindowManager() - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager Destructor"))); - RDKWindowManager::_instance = nullptr; - } - - const string RDKWindowManager::Initialize(PluginHost::IShell* service ) - { - uint32_t result = Core::ERROR_GENERAL; - string retStatus = ""; - - ASSERT(nullptr != service); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mRDKWindowManagerImpl); - ASSERT(0 == mConnectionId); - - SYSLOG(Logging::Startup, (_T("RDKWindowManager::Initialize: PID=%u"), getpid())); - - mCurrentService = service; - - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - mCurrentService->Register(&mRDKWindowManagerNotification); - - mRDKWindowManagerImpl = mCurrentService->Root(mConnectionId, 5000, _T(PLUGIN_RDK_WINDOW_MANAGER_IMPLEMENTATION_NAME)); - - if (nullptr != mRDKWindowManagerImpl) - { - if (Core::ERROR_NONE != (result = mRDKWindowManagerImpl->Initialize(mCurrentService))) - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager::Initialize: Failed to initialise %s"), PLUGIN_RDK_WINDOW_MANAGER_IMPLEMENTATION_NAME)); - retStatus = _T("RDKWindowManager plugin could not be initialised"); - } - else - { - /* Register for notifications */ - mRDKWindowManagerImpl->Register(&mRDKWindowManagerNotification); - /* Invoking Plugin API register to wpeframework */ - Exchange::JRDKWindowManager::Register(*this, mRDKWindowManagerImpl); - } - } - else - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager::Initialize: RDKWindowManagerImpl[%s] object creation failed"), PLUGIN_RDK_WINDOW_MANAGER_IMPLEMENTATION_NAME)); - retStatus = _T("RDKWindowManager plugin could not be initialised"); - } - } - else - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager::Initialize: service is not valid"))); - retStatus = _T("RDKWindowManager plugin could not be initialised"); - } - - if (0 != retStatus.length()) - { - Deinitialize(service); - } - - return retStatus; - } - - void RDKWindowManager::Deinitialize(PluginHost::IShell* service) - { - SYSLOG(Logging::Startup, (_T("RDKWindowManager::Deinitialize: PID=%u"), getpid())); - - ASSERT(mCurrentService == service); - ASSERT(0 == mConnectionId); - - if (nullptr != mRDKWindowManagerImpl) - { - mRDKWindowManagerImpl->Unregister(&mRDKWindowManagerNotification); - Exchange::JRDKWindowManager::Unregister(*this); - - if (nullptr != mCurrentService) - { - mRDKWindowManagerImpl->Deinitialize(mCurrentService); - } - - /* Stop processing: */ - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mRDKWindowManagerImpl->Release(); - - mRDKWindowManagerImpl = nullptr; - - /* It should have been the last reference we are releasing, - * so it should endup in a DESTRUCTION_SUCCEEDED, if not we - * are leaking... */ - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - /* If this was running in a (container) process... */ - if (nullptr != connection) - { - /* Lets trigger the cleanup sequence for - * out-of-process code. Which will guard - * that unwilling processes, get shot if - * not stopped friendly :-) */ - connection->Terminate(); - connection->Release(); - } - } - - if (nullptr != mCurrentService) - { - /* Make sure the Activated and Deactivated are no longer called before we start cleaning up.. */ - mCurrentService->Unregister(&mRDKWindowManagerNotification); - mCurrentService->Release(); - mCurrentService = nullptr; - } - - mConnectionId = 0; - SYSLOG(Logging::Shutdown, (string(_T("RDKWindowManager de-initialised")))); - } - - string RDKWindowManager::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - - void RDKWindowManager::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == mConnectionId) { - ASSERT(nullptr != mCurrentService); - LOGINFO("RDKWindowManager::Deactivated"); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(mCurrentService, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RDKWindowManager/RDKWindowManager.h b/RDKWindowManager/RDKWindowManager.h deleted file mode 100755 index bd2b165..0000000 --- a/RDKWindowManager/RDKWindowManager.h +++ /dev/null @@ -1,114 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { - - namespace Plugin { - - class RDKWindowManager : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IRDKWindowManager::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(RDKWindowManager* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IRDKWindowManager::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - _parent.Deactivated(connection); - } - - void OnUserInactivity(const double minutes) override - { - LOGINFO("OnUserInactivity"); - Exchange::JRDKWindowManager::Event::OnUserInactivity(_parent, minutes); - } - - private: - RDKWindowManager& _parent; - }; - - public: - RDKWindowManager(const RDKWindowManager&) = delete; - RDKWindowManager& operator=(const RDKWindowManager&) = delete; - - RDKWindowManager(); - virtual ~RDKWindowManager(); - - BEGIN_INTERFACE_MAP(RDKWindowManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IRDKWindowManager, mRDKWindowManagerImpl) - END_INTERFACE_MAP - - /* IPlugin methods */ - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: /* members */ - PluginHost::IShell* mCurrentService{}; - uint32_t mConnectionId{}; - Exchange::IRDKWindowManager* mRDKWindowManagerImpl{}; - Core::Sink mRDKWindowManagerNotification; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static RDKWindowManager* _instance; - }; - - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RDKWindowManager/RDKWindowManagerImplementation.cpp b/RDKWindowManager/RDKWindowManagerImplementation.cpp deleted file mode 100755 index 512263f..0000000 --- a/RDKWindowManager/RDKWindowManagerImplementation.cpp +++ /dev/null @@ -1,1618 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "RDKWindowManagerImplementation.h" -#include -#include -#include -#include -#include -#include -#include -#include "UtilsJsonRpc.h" -#include "UtilsUnused.h" -#include "UtilsString.h" - -using namespace std; -using namespace RdkWindowManager; -using namespace Utils; - -extern int gCurrentFramerate; -static bool sRunning = true; - -#define ANY_KEY 65536 -#define KEYCODE_INVALID -1 -#define TRY_LOCK_WAIT_TIME_IN_MS 250 - -namespace WPEFramework { -namespace Plugin { - -SERVICE_REGISTRATION(RDKWindowManagerImplementation, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MAJOR, RDK_WINDOW_MANAGER_API_VERSION_NUMBER_MINOR); -RDKWindowManagerImplementation* RDKWindowManagerImplementation::_instance = nullptr; - -RDKWindowManagerImplementation::RDKWindowManagerImplementation() -: mAdminLock() -, mService(nullptr) -{ - LOGINFO("Create RDKWindowManagerImplementation Instance"); - RDKWindowManagerImplementation::_instance = this; -} - -RDKWindowManagerImplementation::~RDKWindowManagerImplementation() -{ -} - -uint32_t getKeyFlag(std::string modifier) -{ - uint32_t flag = 0; - - if (0 == modifier.compare("ctrl")) - { - flag = RDK_WINDOW_MANAGER_FLAGS_CONTROL; - } - else if (0 == modifier.compare("shift")) - { - flag = RDK_WINDOW_MANAGER_FLAGS_SHIFT; - } - else if (0 == modifier.compare("alt")) - { - flag = RDK_WINDOW_MANAGER_FLAGS_ALT; - } - - return flag; -} - -static std::mutex gRdkWindowManagerMutex; -static std::thread shellThread; -static std::vector> gCreateDisplayRequests; - -CreateDisplayRequest::CreateDisplayRequest(std::string client, std::string displayName, uint32_t displayWidth, uint32_t displayHeight, bool virtualDisplayEnabled, - uint32_t virtualWidth, uint32_t virtualHeight, bool topmost, bool focus) -: mClient(std::move(client)) -, mDisplayName(std::move(displayName)) -, mDisplayWidth(displayWidth) -, mDisplayHeight(displayHeight) -, mVirtualDisplayEnabled(virtualDisplayEnabled) -, mVirtualWidth(virtualWidth) -, mVirtualHeight(virtualHeight) -, mTopmost(topmost) -, mFocus(focus) -, mResult(false) -, mAutoDestroy(true) -{ - if (0 != sem_init(&mSemaphore, 0, 0)) - { - LOGERR("Failed to initialize semaphore: %s", strerror(errno)); - } -} - -CreateDisplayRequest::~CreateDisplayRequest() -{ - if (0 != sem_destroy(&mSemaphore)) - { - LOGERR("Failed to destroy semaphore: %s", strerror(errno)); - } -} - -bool lockRdkWindowManagerMutex() -{ - bool lockAcquired = false; - double startTime = RdkWindowManager::milliseconds(); - while (!lockAcquired && (RdkWindowManager::milliseconds() - startTime) < TRY_LOCK_WAIT_TIME_IN_MS) - { - lockAcquired = gRdkWindowManagerMutex.try_lock(); - } - if (!lockAcquired) - { - LOGERR("unable to get lock for defaulting to normal lock"); - gRdkWindowManagerMutex.lock(); - lockAcquired = true; - } - return lockAcquired; -} - -static bool isClientExists(std::string client) -{ - bool exist = false; - bool retValue = false; - bool lockAcquired = false; - - gRdkWindowManagerMutex.lock(); - for (unsigned int i=0; imClient.compare(client) == 0) - { - exist = true; - break; - } - } - gRdkWindowManagerMutex.unlock(); - - if (!exist) - { - std::vector clientList; - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - retValue = CompositorController::getClients(clientList); - gRdkWindowManagerMutex.unlock(); - if (true == retValue) - { - std::string newClient(std::move(client)); - transform(newClient.begin(), newClient.end(), newClient.begin(), ::tolower); - - if (std::find(clientList.begin(), clientList.end(), newClient) != clientList.end()) - { - exist = true; - } - } - else - { - LOGERR("getClients Failed"); - } - } - - } - return exist; -} - -std::string toLower(const std::string& clientName) -{ - std::string displayName = clientName; - std::transform(displayName.begin(), displayName.end(), displayName.begin(), [](unsigned char c){ return std::tolower(c); }); - return displayName; -} - -Core::hresult RDKWindowManagerImplementation::Initialize(PluginHost::IShell* service) -{ - Core::hresult result = Core::ERROR_NONE; - - ASSERT(nullptr != service); - - mService = service; - - if (nullptr != mService) - { - mService->AddRef(); - - char* waylandDisplay = getenv("WAYLAND_DISPLAY"); - if (NULL != waylandDisplay) - { - LOGINFO("RDKWindowManager WAYLAND_DISPLAY is set to: %s unsetting WAYLAND_DISPLAY", waylandDisplay); - if (0 != unsetenv("WAYLAND_DISPLAY")) - { - LOGERR("Failed, unsetenv for WAYLAND_DISPLAY %s ", strerror(errno)); - } - } - else - { - LOGINFO("RDKWindowManager WAYLAND_DISPLAY is not set"); - } - - mEventListener = std::make_shared(this); - - CompositorController::setEventListener(mEventListener); - - enableInactivityReporting(true); - - static PluginHost::IShell* pluginService = nullptr; - pluginService = mService; - - shellThread = std::thread([=]() { - bool isRunning = true; - gRdkWindowManagerMutex.lock(); - RdkWindowManager::initialize(); - PluginHost::ISubSystem* subSystems(pluginService->SubSystems()); - if (subSystems != nullptr) - { - LOGERR("setting platform and graphics"); - - subSystems->Set(PluginHost::ISubSystem::PLATFORM, nullptr); - subSystems->Set(PluginHost::ISubSystem::GRAPHICS, nullptr); - subSystems->Release(); - } - isRunning = sRunning; - gRdkWindowManagerMutex.unlock(); - while(isRunning) { - const double maxSleepTime = (1000 / gCurrentFramerate) * 1000; - double startFrameTime = RdkWindowManager::microseconds(); - gRdkWindowManagerMutex.lock(); - - while (gCreateDisplayRequests.size() > 0) - { - std::shared_ptr request = gCreateDisplayRequests.front(); - if (!request) - { - gCreateDisplayRequests.erase(gCreateDisplayRequests.begin()); - continue; - } - request->mResult = CompositorController::createDisplay(request->mClient, request->mDisplayName, request->mDisplayWidth, request->mDisplayHeight, request->mVirtualDisplayEnabled, request->mVirtualWidth, request->mVirtualHeight, request->mTopmost, request->mFocus , request->mAutoDestroy); - gCreateDisplayRequests.erase(gCreateDisplayRequests.begin()); - if (0 != sem_post(&request->mSemaphore)) - { - LOGERR("Failed to release CreateDisplayRequest semaphore: %s", strerror(errno)); - } - } - - RdkWindowManager::draw(); - RdkWindowManager::update(); - isRunning = sRunning; - gRdkWindowManagerMutex.unlock(); - double frameTime = (int)RdkWindowManager::microseconds() - (int)startFrameTime; - if (frameTime < maxSleepTime) - { - int sleepTime = (int)maxSleepTime-(int)frameTime; - usleep(sleepTime); - } - } - }); - - LOGINFO("RDKWindowManagerImplementation::Initialized"); - } - else - { - LOGERR("mService is nullptr"); - result = Core::ERROR_GENERAL; - } - - return (result); -} - -void RDKWindowManagerImplementation::Deinitialize(PluginHost::IShell* service) -{ - ASSERT(nullptr != service); - - if (nullptr != mService) - { - mService->Release(); - mService = nullptr; - } - - gRdkWindowManagerMutex.lock(); - RdkWindowManager::deinitialize(); - sRunning = false; - gRdkWindowManagerMutex.unlock(); - - shellThread.join(); - - std::vector clientList; - if (false == CompositorController::getClients(clientList)) - { - LOGERR("getClients Failed"); - } - - std::vector::iterator ptr; - for(ptr=clientList.begin();ptr!=clientList.end();ptr++) - { - if(false == RdkWindowManager::CompositorController::removeListener((*ptr),mEventListener)) - { - LOGERR("CompositorController::removeListener Failed"); - } - } - - RDKWindowManagerImplementation::_instance = nullptr; - - CompositorController::setEventListener(nullptr); - mEventListener = nullptr; - - gRdkWindowManagerMutex.lock(); - for (unsigned int i=0; imSemaphore)) - { - LOGERR("Failed to destroy semaphore: %s", strerror(errno)); - } - gCreateDisplayRequests[i] = nullptr; - } - } - gCreateDisplayRequests.clear(); - - gRdkWindowManagerMutex.unlock(); - - LOGINFO("RDKWindowManagerImplementation::Deinitialized"); -} - -/** - * Register a notification callback - */ -Core::hresult RDKWindowManagerImplementation::Register(INotification *notification) -{ - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mRDKWindowManagerNotification.begin(), mRDKWindowManagerNotification.end(), notification) == mRDKWindowManagerNotification.end()) - { - LOGINFO("Register notification"); - mRDKWindowManagerNotification.push_back(notification); - notification->AddRef(); - } - - mAdminLock.Unlock(); - - return Core::ERROR_NONE; -} - -/** - * Unregister a notification callback - */ -Core::hresult RDKWindowManagerImplementation::Unregister(INotification *notification ) -{ - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - mAdminLock.Lock(); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mRDKWindowManagerNotification.begin(), mRDKWindowManagerNotification.end(), notification); - if (itr != mRDKWindowManagerNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mRDKWindowManagerNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - mAdminLock.Unlock(); - - return status; -} - -void RDKWindowManagerImplementation::RdkWindowManagerListener::onUserInactive(const double minutes) -{ - LOGINFO("RDKWindowManager onUserInactive event received minutes: %f", minutes); - - if ( nullptr == mRDKWindowManagerImpl ) - { - LOGERR("mRDKWindowManagerImpl is null"); - } - else - { - mRDKWindowManagerImpl->dispatchEvent(RDKWindowManagerImplementation::Event::RDK_WINDOW_MANAGER_EVENT_ON_USER_INACTIVITY, JsonValue(minutes)); - } -} - -void RDKWindowManagerImplementation::dispatchEvent(Event event, const JsonValue ¶ms) -{ - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); -} - -void RDKWindowManagerImplementation::Dispatch(Event event, const JsonValue params) -{ - mAdminLock.Lock(); - - std::list::const_iterator index(mRDKWindowManagerNotification.begin()); - - switch(event) { - case RDK_WINDOW_MANAGER_EVENT_ON_USER_INACTIVITY: - while (index != mRDKWindowManagerNotification.end()) - { - LOGINFO("RDKWindowManager Dispatch OnUserInactivity minutes: %f", params.Double()); - - (*index)->OnUserInactivity(params.Double()); - ++index; - } - break; - - default: - LOGWARN("Event[%u] not handled", event); - break; - } - - mAdminLock.Unlock(); -} - -/*** - * @brief Create the display window. - * Creates a display for the specified client using the configuration parameters. - * - * @displayParams[in] : JSON String format with client/callSign, displayName, displayWidth, displayHeight, - * virtualDisplay,virtualWidth,virtualHeight,topmost,focus - * Ex:{\"callsign\": \"org.rdk.YouTube\",\"displayName\": \"test1\",\"displayWidth\": 1920,\"displayHeight\": 1080, - * \"virtualDisplay\": true,\"virtualWidth\": 1920,\"virtualHeight\": 1080,\"topmost\": false,\"focus\": false} - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::CreateDisplay(const string &displayParams) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool result = true; - JsonObject parameters; - - if (displayParams.empty()) - { - LOGERR("displayParams is empty"); - } - else - { - LOGINFO("displayParams :%s", displayParams.c_str()); - - parameters.FromString(displayParams); - - if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - LOGERR("client or callsign"); - } - else - { - string client = ""; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - - string displayName(""); - if (parameters.HasLabel("displayName")) - { - displayName = parameters["displayName"].String(); - } - - uint32_t displayWidth = 0; - if (parameters.HasLabel("displayWidth")) - { - displayWidth = parameters["displayWidth"].Number(); - } - - uint32_t displayHeight = 0; - if (parameters.HasLabel("displayHeight")) - { - displayHeight = parameters["displayHeight"].Number(); - } - - bool virtualDisplay = false; - if (parameters.HasLabel("virtualDisplay")) - { - virtualDisplay = parameters["virtualDisplay"].Boolean(); - } - - uint32_t virtualWidth = 0; - if (parameters.HasLabel("virtualWidth")) - { - virtualWidth = parameters["virtualWidth"].Number(); - } - - uint32_t virtualHeight = 0; - if (parameters.HasLabel("virtualHeight")) - { - virtualHeight = parameters["virtualHeight"].Number(); - } - - bool topmost = false; - if (parameters.HasLabel("topmost")) - { - topmost = parameters["topmost"].Boolean(); - } - - bool focus = false; - if (parameters.HasLabel("focus")) - { - focus = parameters["focus"].Boolean(); - } - - result = createDisplay(client, displayName, displayWidth, displayHeight, - virtualDisplay, virtualWidth, virtualHeight, topmost, focus); - - if (false == result) - { - LOGERR("failed to create display : %s, displayName:%s, displayWidth:%u, displayHeight:%u, virtualDisplay:%u, virtualWidth:%u, virtualHeight:%u, topmost:%u, focus:%u", - client.c_str(), displayName.c_str(), displayWidth, displayHeight, virtualDisplay, virtualWidth, virtualHeight, topmost, focus); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - -/*** - * @brief Create the display window. - * Creates a display for the specified client using the configuration parameters. - * - * @clients[out] : get the array of clients as a JSON string format - * Ex: [\"org.rdk.youttube\",\"org.rdk.netflix\"] - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::GetClients(string &clients) const -{ - Core::hresult status = Core::ERROR_GENERAL; - bool retValue = false; - std::vector clientList; - JsonArray clientsArray; - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - retValue = CompositorController::getClients(clientList); - gRdkWindowManagerMutex.unlock(); - } - - if (true == retValue) - { - for (size_t i = 0; i < clientList.size(); i++) - { - clientsArray.Add(clientList[i]); - } - - if (clientsArray.IsSet()) - { - clientsArray.ToString(clients); - LOGINFO("clients: %s", clients.c_str()); - } - else - { - LOGWARN("There is no clients"); - } - status = Core::ERROR_NONE; - } - else - { - LOGERR("getClients Falied"); - } - - return status; -} - -/* @brief AddKeyIntercept for the client. - * A method to intercept key events before dispatched, allowing blocking of specific keys - * - * @intercept[in] : JSON String format with client/callSign, keyCode, modifiers - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::AddKeyIntercept(const string &intercept) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (intercept.empty()) - { - LOGERR("intercept is empty"); - } - else - { - LOGINFO("intercept :%s", intercept.c_str()); - parameters.FromString(intercept); - if (!parameters.HasLabel("keyCode")) - { - LOGERR("please specify keyCode"); - } - else if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - LOGERR("please specify client or callsign"); - } - else - { - /*optional param */ - const JsonArray modifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - - const uint32_t keyCode = parameters["keyCode"].Number(); - string client = ""; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (false == addKeyIntercept(keyCode, modifiers, client)) - { - LOGERR("failed to add key intercept"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - -/* @brief AddKeyIntercepts for the clients. - * A method to add mutiple key interceptors to enabling blocking of several keys for mutiple client - * @intercepts[in] : JSON String format with client/callSign, keyCode, modifiers - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::AddKeyIntercepts(const string &intercepts) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (intercepts.empty()) - { - LOGERR("intercepts is empty"); - } - else - { - LOGINFO("intercepts :%s", intercepts.c_str()); - parameters.FromString(intercepts); - if (!parameters.HasLabel("intercepts")) - { - LOGERR("please specify intercepts"); - } - else - { - const JsonArray keyIntercepts = parameters["intercepts"].Array(); - if (false == addKeyIntercepts(keyIntercepts)) - { - LOGERR("failed to add some key intercepts due to missing parameters or wrong format"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - -/* @brief RemoveKeyIntercept of the client. - * Intercept key is removed from that client - * - * @intercept[in] : JSON String format with client/callSign, keyCode, modifiers - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::RemoveKeyIntercept(const string &intercept) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (intercept.empty()) - { - LOGERR("intercept is empty"); - } - else - { - LOGINFO("intercept :%s", intercept.c_str()); - parameters.FromString(intercept); - - if (!parameters.HasLabel("keyCode")) - { - LOGERR("please specify keyCode"); - } - else if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - LOGERR("please specify client or callsign"); - } - else - { - /* optional param */ - const JsonArray modifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - - uint32_t keyCode = parameters["keyCode"].Number(); - /* check for * parameter */ - JsonValue keyCodeValue = parameters["keyCode"]; - if (keyCodeValue.Content() == JsonValue::type::STRING) - { - std::string keyCodeStringValue = parameters["keyCode"].String(); - if (keyCodeStringValue.compare("*") == 0) - { - keyCode = 255; - } - } - string client = ""; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (false == removeKeyIntercept(keyCode, modifiers, client)) - { - LOGERR("failed to remove key intercept"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - - -/* @brief AddKeyListener for the client. - * A method to handle key events ,enabling custom actions when specific keys are injected/pressed for that client - * - * @keyListeners[in] : JSON String format with client/callSign, keys:keyCode/nativeKeyCode,modifiers,activate.propagate - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::AddKeyListener(const string &keyListeners) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (keyListeners.empty()) - { - LOGERR("keyListeners is empty"); - } - else - { - LOGINFO("keyListeners :%s", keyListeners.c_str()); - parameters.FromString(keyListeners); - if (!parameters.HasLabel("keys")) - { - LOGERR("please specify keys"); - } - else if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - LOGERR("please specify client or callsign"); - } - else - { - const JsonArray keys = parameters["keys"].Array(); - string client = ""; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (false == addKeyListeners(client, keys)) - { - LOGERR("failed to add key listeners"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - - -/* @brief RemvoeKeyListener for the client. - * A method to remove previously added keyEvent listeners , stopping them from handling key events - * - * @keyListeners[in] : JSON String format with client/callSign, keys:keyCode/nativeKeyCode,modifiers - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::RemoveKeyListener(const string &keyListeners) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (keyListeners.empty()) - { - LOGERR("keyListeners is empty"); - } - else - { - LOGINFO("keyListeners :%s", keyListeners.c_str()); - parameters.FromString(keyListeners); - if (!parameters.HasLabel("keys")) - { - LOGERR("please specify keys"); - } - else if (!parameters.HasLabel("client") && !parameters.HasLabel("callsign")) - { - LOGERR("please specify client"); - } - else - { - const JsonArray keys = parameters["keys"].Array(); - string client= ""; - if (parameters.HasLabel("client")) - { - client = parameters["client"].String(); - } - else - { - client = parameters["callsign"].String(); - } - if (false == removeKeyListeners(client, keys)) - { - LOGERR("failed to remove key listeners"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - - -/* @brief InjectKey . - * A method to programmtically simulate key events - * - * @keyCode[in] key to simulate , @modifiers[in] like ctrl, alt, shift - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::InjectKey(uint32_t keyCode, const string &modifiers) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - JsonArray keyModifiers = JsonArray(); - - if (modifiers.empty()) - { - LOGINFO("modifiers is empty"); - } - else - { - LOGINFO("modifiers :%s", modifiers.c_str()); - parameters.FromString(modifiers); - /* optional param */ - keyModifiers = parameters.HasLabel("modifiers") ? parameters["modifiers"].Array() : JsonArray(); - } - - if (false == injectKey(keyCode, keyModifiers)) - { - LOGERR("failed to inject key"); - } - else - { - status = Core::ERROR_NONE; - } - return status; -} - -/* @brief GenerateKey . - * A method to programmtically simulate mutiple key events for the client - * - * @keys[in] keys:keyCode,modifiers,delay , @client[in] for the client - * @return ERROR_NONE if success , ERROR_GENERAL if failure. - */ -Core::hresult RDKWindowManagerImplementation::GenerateKey(const string& keys, const string& client) -{ - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - - if (keys.empty()) - { - LOGERR("keys is empty"); - } - else - { - LOGINFO("keys :%s", keys.c_str()); - parameters.FromString(keys); - if (!parameters.HasLabel("keys")) - { - LOGERR("please specify keyInputs"); - } - else - { - const JsonArray keyInputs = parameters["keys"].Array(); - - if (false == generateKey(client, keyInputs)) - { - LOGERR("failed to generate keys"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - return status; -} - -/*** - @brief Enables the inactivity reporting feature -* -* @enable[in] : True/False,to enable/disable the feature -* @return : Core:: -*/ -Core::hresult RDKWindowManagerImplementation::EnableInactivityReporting(const bool enable) -{ - Core::hresult status = Core::ERROR_GENERAL; - - LOGINFO("EnableInactivityReporting Entered"); - - if (false == enableInactivityReporting(enable)) - { - LOGERR("failed to set inactivity notification"); - } - else - { - status = Core::ERROR_NONE; - } - return status; -} - -/*** -* @brief Sets the inactivity time interval -* @interval[in] :Time interval in minutes -* @return : Core:: -*/ -Core::hresult RDKWindowManagerImplementation::SetInactivityInterval(const uint32_t interval) -{ - Core::hresult status = Core::ERROR_GENERAL; - - LOGINFO("SetInactivityInterval Entered"); - - if (false == setInactivityInterval(interval)) - { - LOGERR("failed to reset inactivity time"); - } - else - { - status = Core::ERROR_NONE; - } - return status; -} - -/*** -* @brief ResetInactivityTime:Resets the inactivity time interval -* @return : Core:: -*/ -Core::hresult RDKWindowManagerImplementation::ResetInactivityTime() -{ - Core::hresult status = Core::ERROR_GENERAL; - - LOGINFO("ResetInactivityTime Entered"); - - if (false == resetInactivityTime()) - { - LOGERR("failed to reset inactivity time"); - } - else - { - status = Core::ERROR_NONE; - } - return status; -} - -/*** - * @brief Enable or disable key repeats. - * Set the key repeat functionality for input events. - * - * @param[in] enable : Boolean flag to enable (true) or disable (false) key repeats. - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::EnableKeyRepeats(bool enable) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - if (CompositorController::enableKeyRepeats(enable)) - { - status = Core::ERROR_NONE; - } - else - { - LOGERR("Failed to enabled key repeats"); - } - gRdkWindowManagerMutex.unlock(); - } - - return status; -} - - /*** - * @brief Get the status of key repeat functionality. - * Retrieves whether the key repeat functionality is currently enabled or disabled. - * - * @param[out] keyRepeat : the key repeat status(true if enabled, false if disabled). - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::GetKeyRepeatsEnabled(bool &keyRepeat) const -{ - Core::hresult status = Core::ERROR_GENERAL; - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - if (CompositorController::getKeyRepeatsEnabled(keyRepeat)) - { - status = Core::ERROR_NONE; - } - else - { - LOGERR("Failed to retrieve key repeat status"); - } - gRdkWindowManagerMutex.unlock(); - } - - return status; -} - -/*** - * @brief Enable or disable key input handling. - * Set whether key inputs should be ignored or processed. - * - * @param[in] ignore : true to 'ignore' or false to 'not ignore' key inputs. - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::IgnoreKeyInputs(bool ignore) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - if (CompositorController::ignoreKeyInputs(ignore)) - { - status = Core::ERROR_NONE; - } - else - { - LOGERR("Failed to ignore key inputs"); - } - gRdkWindowManagerMutex.unlock(); - } - return status; -} - - /*** - * @brief Enable or disable input events for specified clients. - * Controls whether input events are processed or ignored for specified clients. - * - * @param[in] clients : JSON String format specifying the clients for which input events should be enabled or disabled. - * Example: {"clients": ["testapp"]} - * @param[in] enable : flag to enable (true) or disable (false) input events for the specified clients. - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::EnableInputEvents(const string &clients, bool enable) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool result = true; - JsonObject parameters; - - if (clients.empty()) - { - LOGERR("Clients parameter is empty"); - result = false; - } - - else if (!parameters.FromString(clients)) - { - LOGERR("Invalid JSON string in clients parameter"); - result = false; - } - - else - { - const JsonArray clientArray = parameters.HasLabel("clients") ? parameters["clients"].Array() : JsonArray(); - gRdkWindowManagerMutex.lock(); - if (clientArray.Length() > 0) - { - for (int i = 0; i < clientArray.Length(); i++) - { - if (clientArray[i].Content() != JsonValue::type::STRING) - { - LOGWARN("Skipping client at index %d due to invalid format", i); - result = false; - continue; - } - - const string clientName = clientArray[i].String(); - - if (clientName == "*") - { - std::vector clientList; - CompositorController::getClients(clientList); - for (const auto& client : clientList) - { - result = result && CompositorController::enableInputEvents(client, enable); - } - break; - } - else - { - result = result && CompositorController::enableInputEvents(clientName, enable); - } - } - } - else - { - LOGERR("'clientArray is missing"); - result = false; - } - - gRdkWindowManagerMutex.unlock(); - - if (!result) - { - LOGERR("Failed to Enable/Disable input events"); - } - else - { - status = Core::ERROR_NONE; - } - } - return status; -} - -/*** - * @brief Configure key repeat settings. - * Allows enabling or disabling key repeat functionality and setting the initial delay and repeat interval. - * - * @param[in] input : Specifies the type of input device for the configuration. - * @param[in] keyConfig : JSON String format specifying the key repeat configuration. - * Example: {"input": "keyboard","keyConfig": "{\"enabled\":true,\"initialDelay\":500,\"repeatInterval\":100}} - * - * @return : Core:: - */ -Core::hresult RDKWindowManagerImplementation::KeyRepeatConfig(const string &input, const string &keyConfig) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool enabled = false; - int32_t initialDelay = 0; - int32_t repeatInterval = 0; - - JsonObject config; - config.FromString(keyConfig); - - if (!input.empty() && input != "default" && input != "keyboard") - { - LOGERR("Unsupported input type: %s", input.c_str()); - } - else if (!config.HasLabel("enabled")) - { - LOGERR("Missing 'enabled' parameter in keyConfig"); - } - else if (!config.HasLabel("initialDelay")) - { - LOGERR("Missing 'initialDelay' parameter in keyConfig"); - } - else if (!config.HasLabel("repeatInterval")) - { - LOGERR("Missing 'repeatInterval' parameter in keyConfig"); - } - else - { - enabled = config["enabled"].Boolean(); - initialDelay = config["initialDelay"].Number(); - repeatInterval = config["repeatInterval"].Number(); - - gRdkWindowManagerMutex.lock(); - CompositorController::setKeyRepeatConfig(enabled, initialDelay, repeatInterval); - gRdkWindowManagerMutex.unlock(); - - status = Core::ERROR_NONE; - } - - return status; -} - -/*** - * @brief Create the display window. - * Creates a display for the specified client using the configuration parameters. - * - * @client[in] : client/callsign, Ex: westerostest, org.rdk.YouTube - * @displayName[in] : Optional - Name of the display - * @displayWidth[in] : Optional - width of the creating display - * @displayWidth[in] : Optional - width of the creating display - * @displayHeight[in] : Optional - height of the creating display - * @virtualDisplay[in]: Optional - virtual display is required or not - * @virtualWidth[in] : Optional - width of the virtual display - * @virtualHeight[in] : Optional - height of the virtual display - * @topmost[in] : Optional - topmost is required or not true/false - * @focus[in] : Optional - focus is required or not - * @return : Optional - true/false - */ -bool RDKWindowManagerImplementation::createDisplay(const string& client, const string& displayName, const uint32_t displayWidth, const uint32_t displayHeight, - const bool virtualDisplay, const uint32_t virtualWidth, const uint32_t virtualHeight, - const bool topmost, const bool focus) -{ - bool ret = false; - - if (!isClientExists(client)) - { - bool lockAcquired = false; - gRdkWindowManagerMutex.lock(); - std::shared_ptr request = std::make_shared(client, displayName, displayWidth, displayHeight, virtualDisplay, virtualWidth, virtualHeight, topmost, focus); - gCreateDisplayRequests.push_back(request); - gRdkWindowManagerMutex.unlock(); - - if (-1 == sem_wait(&request->mSemaphore)) - { - LOGERR("CreateDisplayRequest: sem_wait failed: %s", strerror(errno)); - } - ret = request->mResult; - - if (ret) - { - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - if (false == RdkWindowManager::CompositorController::addListener(client, mEventListener)) - { - LOGERR("CompositorController::addListener Failed"); - } - gRdkWindowManagerMutex.unlock(); - } - } - } - else - { - LOGERR("Client: %s already exist", client.c_str()); - } - - return ret; -} - -bool RDKWindowManagerImplementation::enableInactivityReporting(const bool enable) -{ - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - if (lockAcquired) - { - RdkWindowManager::CompositorController::enableInactivityReporting(enable); - gRdkWindowManagerMutex.unlock(); - } - return true; -} - -bool RDKWindowManagerImplementation::addKeyIntercept(const uint32_t& keyCode, const JsonArray& modifiers, const string& client) -{ - uint32_t flags = 0; - for (unsigned int i=0; i properties; - if (keyInfo.HasLabel("activate")) - { - bool activate = keyInfo["activate"].Boolean(); - properties["activate"] = activate; - } - if (keyInfo.HasLabel("propagate")) - { - bool propagate = keyInfo["propagate"].Boolean(); - properties["propagate"] = propagate; - } - - if (keyInfo.HasLabel("keyCode")) - { - result = RdkWindowManager::CompositorController::addKeyListener(client, keyCode, flags, properties); - } - else - { - result = RdkWindowManager::CompositorController::addNativeKeyListener(client, keyCode, flags, properties); - } - } - else - { - LOGERR("Neither keyCode nor nativeKeyCode provided"); - } - - if (result == false) - { - break; - } - } - gRdkWindowManagerMutex.unlock(); - return result; -} - -bool RDKWindowManagerImplementation::removeKeyListeners(const string& client, const JsonArray& keys) -{ - gRdkWindowManagerMutex.lock(); - - bool result = true; - - for (unsigned int i=0; i clientList; - RdkWindowManager::CompositorController::getClients(clientList); - std::transform(keyClient.begin(), keyClient.end(), keyClient.begin(), ::tolower); - if (std::find(clientList.begin(), clientList.end(), keyClient) != clientList.end()) - { - targetFound = true; - } - } - if (targetFound || keyClient == "") - { - ret = RdkWindowManager::CompositorController::generateKey(keyClient, keyCode, flags, std::move(virtualKey)); - } - gRdkWindowManagerMutex.unlock(); - } - } - return ret; -} - -bool RDKWindowManagerImplementation::setInactivityInterval(const uint32_t interval) -{ - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - try - { - RdkWindowManager::CompositorController::setInactivityInterval((double)interval); - LOGINFO("RDKWindowManager setInactivity for Interval:%d",interval); - } - catch (...) - { - LOGERR("RDKWindowManager unable to set inactivity interval "); - } - if (lockAcquired) - { - gRdkWindowManagerMutex.unlock(); - } - return true; -} - -bool RDKWindowManagerImplementation::resetInactivityTime() -{ - bool lockAcquired = false; - - lockAcquired = lockRdkWindowManagerMutex(); - try - { - RdkWindowManager::CompositorController::resetInactivityTime(); - LOGINFO("RDKWindowManager inactivity time reset"); - } - catch (...) - { - LOGERR("RDKWindowManager unable to reset inactivity time "); - } - if (lockAcquired) - { - gRdkWindowManagerMutex.unlock(); - } - return true; -} -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RDKWindowManager/RDKWindowManagerImplementation.h b/RDKWindowManager/RDKWindowManagerImplementation.h deleted file mode 100755 index 95472cf..0000000 --- a/RDKWindowManager/RDKWindowManagerImplementation.h +++ /dev/null @@ -1,189 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include "tracing/Logging.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - struct CreateDisplayRequest - { - CreateDisplayRequest(std::string client, std::string displayName, uint32_t displayWidth=0, uint32_t displayHeight=0, bool virtualDisplayEnabled=false, - uint32_t virtualWidth=0, uint32_t virtualHeight=0, bool topmost = false, bool focus = false); - - ~CreateDisplayRequest(); - - std::string mClient; - std::string mDisplayName; - uint32_t mDisplayWidth; - uint32_t mDisplayHeight; - bool mVirtualDisplayEnabled; - uint32_t mVirtualWidth; - uint32_t mVirtualHeight; - bool mTopmost; - bool mFocus; - sem_t mSemaphore; - bool mResult; - bool mAutoDestroy; - }; - - class RDKWindowManagerImplementation : public Exchange::IRDKWindowManager{ - public: - RDKWindowManagerImplementation(); - ~RDKWindowManagerImplementation() override; - - RDKWindowManagerImplementation(const RDKWindowManagerImplementation&) = delete; - RDKWindowManagerImplementation& operator=(const RDKWindowManagerImplementation&) = delete; - - BEGIN_INTERFACE_MAP(RDKWindowManagerImplementation) - INTERFACE_ENTRY(Exchange::IRDKWindowManager) - END_INTERFACE_MAP - - public: - enum Event { - RDK_WINDOW_MANAGER_EVENT_UNKNOWN, - RDK_WINDOW_MANAGER_EVENT_ON_USER_INACTIVITY - }; - - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(RDKWindowManagerImplementation *rdkWindowManagerImplementation, Event event, JsonValue ¶ms) - : _rdkWindowManagerImplementation(rdkWindowManagerImplementation) - , _event(event) - , _params(params) { - if (_rdkWindowManagerImplementation != nullptr) { - _rdkWindowManagerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (_rdkWindowManagerImplementation != nullptr) { - _rdkWindowManagerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(RDKWindowManagerImplementation *rdkWindowManagerImplementation, Event event, JsonValue params) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(rdkWindowManagerImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(rdkWindowManagerImplementation, event, params))); -#endif - } - - virtual void Dispatch() { - _rdkWindowManagerImplementation->Dispatch(_event, _params); - } - private: - RDKWindowManagerImplementation *_rdkWindowManagerImplementation; - const Event _event; - const JsonValue _params; - }; - - public: - Core::hresult Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - Core::hresult Register(INotification *notification) override; - Core::hresult Unregister(INotification *notification) override; - Core::hresult CreateDisplay(const string &displayParams) override; - Core::hresult GetClients(string &clients) const override; - Core::hresult AddKeyIntercept(const string &intercept) override; - Core::hresult AddKeyIntercepts(const string &intercepts) override; - Core::hresult RemoveKeyIntercept(const string &intercept) override; - Core::hresult AddKeyListener(const string &keyListeners) override; - Core::hresult RemoveKeyListener(const string &keyListeners) override; - Core::hresult InjectKey(uint32_t keyCode, const string &modifiers) override; - Core::hresult GenerateKey(const string& keys, const string& client) override; - Core::hresult EnableInactivityReporting(const bool enable) override;; - Core::hresult SetInactivityInterval(const uint32_t interval) override; - Core::hresult ResetInactivityTime() override; - Core::hresult EnableKeyRepeats(bool enable) override; - Core::hresult GetKeyRepeatsEnabled(bool &keyRepeat) const override; - Core::hresult IgnoreKeyInputs(bool ignore) override; - Core::hresult EnableInputEvents(const string &clients, bool enable) override; - Core::hresult KeyRepeatConfig(const string &input, const string &keyConfig) override; - - private: /*internal methods*/ - bool createDisplay(const string& client, const string& displayName, const uint32_t displayWidth = 0, const uint32_t displayHeight = 0, - const bool virtualDisplay = false, const uint32_t virtualWidth = 0, const uint32_t virtualHeight = 0, - const bool topmost = false, const bool focus = false); - bool getClients(JsonArray& clients); - bool addKeyIntercept(const uint32_t& keyCode, const JsonArray& modifiers, const string& client); - bool addKeyIntercepts(const JsonArray& intercepts); - bool removeKeyIntercept(const uint32_t& keyCode, const JsonArray& modifiers, const string& client); - bool addKeyListeners(const string& client, const JsonArray& listeners); - bool removeKeyListeners(const string& client, const JsonArray& listeners); - bool injectKey(const uint32_t& keyCode, const JsonArray& modifiers); - bool generateKey(const string& client, const JsonArray& keyInputs); - bool enableInactivityReporting(const bool enable); - bool setInactivityInterval(const uint32_t interval); - bool resetInactivityTime(); - - void dispatchEvent(Event event, const JsonValue ¶ms); - void Dispatch(Event event, const JsonValue params); - - private: /*internal methods*/ - class RdkWindowManagerListener : public RdkWindowManager::RdkWindowManagerEventListener { - public: - RdkWindowManagerListener(RDKWindowManagerImplementation* rdkWindowManagerImpl) - : mRDKWindowManagerImpl(rdkWindowManagerImpl) - { - } - - ~RdkWindowManagerListener() - { - } - - /* Events listeners */ - virtual void onUserInactive(const double minutes); - - private: - RDKWindowManagerImplementation *mRDKWindowManagerImpl; - }; - - public/*members*/: - static RDKWindowManagerImplementation* _instance; - - private: - mutable Core::CriticalSection mAdminLock; - std::list mRDKWindowManagerNotification; - PluginHost::IShell* mService{}; - std::shared_ptr mEventListener; - - friend class Job; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RDKWindowManager/README.md b/RDKWindowManager/README.md deleted file mode 100755 index d7e4018..0000000 --- a/RDKWindowManager/README.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------ -# RDKWindowManager - -## Versions -`org.rdk.RDKWindowManager.1` - -## Methods: -``` -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKWindowManager.1.addKeyIntercept", "params":{"keyCode": 10, "modifiers": ["alt", "shift"], "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKWindowManager.1.removeKeyIntercept", "params":{"keyCode": 10, "modifiers": ["alt", "shift"], "client": "org.rdk.Netflix"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method":"org.rdk.RDKWindowManager.1.getClients", "params":{}}' http://127.0.0.1:9998/jsonrpc -``` - -## Responses -``` -addKeyIntercept: -{"jsonrpc":"2.0", "id":3, "result": {} } - -removeKeyIntercept: -{"jsonrpc":"2.0", "id":3, "result": {} } - -getClients: -{"jsonrpc":"2.0", "id":3, "result": { "clients": ["org.rdk.Netflix", "org.rdk.RDKBrowser2"]} } - -``` - -## Events -``` -none -``` diff --git a/RDKWindowManager/test/RDKWMJsonL3Test.sh b/RDKWindowManager/test/RDKWMJsonL3Test.sh deleted file mode 100755 index fe8cb2b..0000000 --- a/RDKWindowManager/test/RDKWMJsonL3Test.sh +++ /dev/null @@ -1,1143 +0,0 @@ -#!/bin/sh - -### -# If not stated otherwise in this file or this component's LICENSE -# file the following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -### - -successCount=0 -failuresCount=0 -testAppTimeOut=15s - -testHelp() { - echo "Run Command to test the methods" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - echo "SI.No. | TestCase | Command | Test Details" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "1" "testCreateDisplay1" "RDKWMJsonL3Test.sh testCreateDisplay1" "1. Without resolution, it will invoke the createDisplay function with the Westerosapp client." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. It will invoke the getClients function to verify that the westerostest client is present." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. The westerostest client will connect to the westeros_test app, which will then launch." - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "2" "testCreateDisplay2" "RDKWMJsonL3Test.sh testCreateDisplay2" "1. With given resolution, it will invoke the createDisplay function with the Westerosapp client." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. It will invoke the getClients function to verify that the westerostest client is present." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. The westerostest client will connect to the westeros_test app, which will then launch." - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "3" "testCreateDisplay3" "RDKWMJsonL3Test.sh testCreateDisplay3" "1. It will invoke the createDisplay function without any client." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Expecting ERROR_GENERAL in error code" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "4" "testGetClients1" "RDKWMJsonL3Test.sh testGetClients1" "1. It will invoke the getClients function without calling the createDisplay and ensure no clients are present" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "Note: This test was run without first performing any createDisplay." - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "5" "testGetClients2" "RDKWMJsonL3Test.sh testGetClients2" "1. It will invoke the createDisplay function with client only." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. It will invoke the getClients function to verify that the client is present." - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "6" "testListeners" "RDKWMJsonL3Test.sh testListeners" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. AddKeyListener with keyCode 70 with client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. GenerateKey for keyCode 70 without client - f should be seen on the screen if focused is not none" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. RemoveKeyListener for keyCode 70 with client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. Deactivate webkitBrowser,internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "7" "testIntercept1" "RDKWMJsonL3Test.sh testIntercept1" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. AddKeyIntercept with keyCode 65 with shift with client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. InjectKey for keyCode 65 with Modifers shift - A should be seen on the google screen if focused is not none " - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. RemoveKeyIntercept with keyCode 65 with shift,client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. Deactivate webkitBrowser, internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "8" "testIntercept2" "RDKWMJsonL3Test.sh testIntercept2" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. AddKeyIntercept with keyCode 66 with client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. GenerateKey for keyCode 66 with shift,client googletestapp - B should be seen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. RemoveKeyIntercept with keyCode 66 with client googletestapp" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. Deactivate webkitBrowser,internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "9" "testIntercept3" "RDKWMJsonL3Test.sh testIntercept3" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Create and Launch westeros test" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. AddKeyIntercept with keyCode 67 with shift, client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. InjectKey for keyCode 67 and 68 with shift - D should be seen on the screen if focused is not none" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. RemoveKeyIntercept with keyCode 67 with shift,client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "6. kill westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "7. Deactivate webkitBrowser, internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "10" "testIntercept4" "RDKWMJsonL3Test.sh testIntercept4" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Create and Launch westeros test" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. AddKeyIntercept with keyCode 67 with shift, client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. GenerateKey for keyCode 67 and 68 with shift ,without client - D should be seen on the screen if focused is not none" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. RemoveKeyIntercept with keyCode 67 with shift,client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "6. kill westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "7. Deactivate webkitBrowser, internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "11" "testGenerateKey" "RDKWMJsonL3Test.sh testGenerateKey" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Create and Launch westeros test with focus as true" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. GenerateKey for keyCode 67 and 68 without client specified - C and D should not be seen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. GenerateKey for keyCode 67 and 68 with client specified - C and D should be seen on the screen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. kill westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "6. Deactivate webkitBrowser, internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "12" "testIntercepts" "RDKWMJsonL3Test.sh testIntercepts" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Create and Launch westeros test" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. AddKeyIntercepts for keyCode 75 and 76 with shift,client googletestapp & 80 with shift and 79 with no modifiers,client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. GenerateKey for keyCode 79 with no modifiers and 76 with shift, client - o and L should be seen on the screen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. GenerateKey for keyCode 79 with no modifiers and 76 with shift, without client - L should be seen on the screen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "6. RemoveKeyIntercept for keyCode 79 with client westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "7. kill westerostest" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "8. Deactivate webkitBrowser, internally kills the client googletestapp" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "13" "testInjectGenerateKey" "RDKWMJsonL3Test.sh testInjectGenerateKey" "1. Create and Launch GoogleBrowser with webkitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. injectKey for keyCode 71 - G should be seen if focused is not none " - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. GenerateKey for keyCode 72 and 73 with shift,client - h and I should be seen" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. Deactivate webkitBrowser internally kill the client" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "14" "testKeyListenersFailures" "RDKWMJsonL3Test.sh testKeyListenersFailures" "1. AddKeyListener with both keyCode and NativeKeyCode present" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "2. Expecting ERROR_GENERAL in error code" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "3. AddKeyListener without both keyCode and NativeKeyCode" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "4. Expecting ERROR_GENERAL in error code" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "5. RemoveKeyListener with both keyCode and NativeKeyCode" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "6. Expecting ERROR_GENERAL in error code" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "7. RemoveKeyListener without both keyCode and NativeKeyCode" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "" "8. Expecting ERROR_GENERAL in error code" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "15" "testInactivity1" "RDKWMJsonL3Test.sh testInactivity1" "1. Enable the inactivity reporting feature." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2. Set inactivity time of 1minute." - echo "---------------------|------------------------------------------|--------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "16" "testInactivity2" "RDKWMJsonL3Test.sh testInactivity2" "1. Disable inactivity reportingfeature." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2. Set inactivity time of 1minute." - echo "---------------------|------------------------------------------|--------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "17" "testInactivity3" "RDKWMJsonL3Test.sh testInactivity3" "1. Enable Inactivity feature." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Set inactivity time interval of 1minute" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Wait for 40sec,Reset the inactivity." - echo "---------------------|------------------------------------------|--------------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "18" "testInactivity4" "RDKWMJsonL3Test.sh testInactivity4" "1. Enable Inactivity reporting feature." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2. Set inactivity time of 1min and wait for 40secs." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3. Inject key" - echo "--------|----------------------|------------------------------------------|-------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "19" "testGetKeyRepeatsEnabled" "RDKWMJsonL3Test.sh testGetKeyRepeatsEnabled" "1. Call the testEnableKeyRepeats function to disable the key repeat feature." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.invoke the org.rdk.RDKWindowManager.getKeyRepeatsEnabled method " - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Verify that the response is false, indicating that key repeats are disabled." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "4.Call the testEnableKeyRepeats function to enable the key repeat feature" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "5.Invoke the org.rdk.RDKWindowManager.getKeyRepeatsEnabled method " - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "6.Verify that the response is true, confirming that key repeats are enabled" - echo "--------|----------------------|------------------------------------------|---------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "20" "testInputEventEnable" "RDKWMJsonL3Test.sh testInputEventEnable" "1. create a display using the createDisplay API." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Load the Google homepage in the WebKitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "4.Enable input events for the testapp client by calling the testSetInputEventEnable function." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "5.Attempt to inject a key using the injectKey API" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "6.Verify that the response is null" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "7.Confirm that the key injection is accepted on the WebKitBrowser application side when input events are Enabled" - echo "--------|----------------------|------------------------------------------|--------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "21" "testInputEventDisble" "RDKWMJsonL3Test.sh testInputEventDisable" "1. create a display using the createDisplay API." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Load the Google homepage in the WebKitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "4.Disable input events for the testapp client by calling the testSetInputEventDisable function." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "5.Attempt to inject a key using the injectKey API" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "6.Verify that the response is nul" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "7.Confirm that the key injection is NOT accepted on the WebKitBrowser application side when input events are Enabled" - echo "--------|----------------------|------------------------------------------|--------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "22" "testIgnoreKeyInputsEnable" "RDKWMJsonL3Test.sh testIgnoreKeyInputsEnable" "The RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE feature must be enabled (set to 1) for this function to execute." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "1.Create a display using the createDisplay API." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Load the Google homepage in the WebKitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "4.Enable ignore key input for the testapp client by calling the IgnoreKeyInputs function." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "5.Attempt to press a key using the Remote Controller" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "6.Confirm that the key press is NOT accepted on the WebKitBrowser application side when IgnoreKeyInput is Enabled" - echo "--------|----------------------|------------------------------------------|----------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "23" "testIgnoreKeyInputsDisable" "RDKWMJsonL3Test.sh testIgnoreKeyInputsDisable" "The RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE feature must be enabled (set to 1) for this function to execute." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "1.Create a display using the createDisplay API." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Load the Google homepage in the WebKitBrowser" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "4.Disable ignore key input for the testapp client by calling the IgnoreKeyInputs function." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "5.Attempt to press a key using the Remote Controller" - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "6.Confirm that the key press is accepted on the WebKitBrowser application side when IgnoreKeyInput is Disabled" - echo "--------|----------------------|------------------------------------------|----------------------------------------------------------------------" printf "%-7s | %-20s | %-40s | %-70s\n" "24" "testKeyRepeatConfigUnsupportedInput" "RDKWMJsonL3Test.sh testKeyRepeatConfigUnsupportedInput" "1. Attempt to configure keyRepeatConfig for an unsupported input type (e.g., "mouse") using the API.." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Verify that the response contains an error with code: 1 and message: "ERROR_GENERAL"." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Confirm that the key repeat configuration is not applied due to the missing parameter." - echo "--------|----------------------|------------------------------------------|------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "25" "testKeyRepeatConfigMissingEnabled" "RDKWMJsonL3Test.sh testKeyRepeatConfigMissingEnabled" "1. Invoke the keyRepeatConfig API for the "default" input, omitting the enabled parameter." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "2.Verify that the response contains an error with code: 1 and message: "ERROR_GENERAL"." - printf "%-7s | %-20s | %-40s | %-70s\n" "" "" "3.Confirm that the key repeat configuration is not applied due to the missing parameter." - echo "--------|----------------------|------------------------------------------|---------------------------------------------------------------------" - printf "%-7s | %-20s | %-40s | %-70s\n" "26" "testAll" "RDKWMJsonL3Test.sh testAll" "1. Run all the tests" - echo "---------------------|------------------------------------------|--------------------------------------------------------------------------" -} - -#killWesterosTestApp -killWesterosTestApp() -{ - PID=$(ps -eo pid,comm | grep "westeros_test" | grep -v "grep" | awk '{print $1}') - kill ${PID} -} - -#createDisplayAndLaunchGoogleBrowserWithWebkitBrowser -createDisplayAndLaunchGoogleBrowser() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"googletestapp\", \"displayName\": \"wst-webkitbrowser\"}"}}' - expectedResult='null' - testAPI "CreateDisplayForGoogle" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}' - expectedResult='null' - testAPI "WebkitBrowserActivate" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}' - expectedResult='null' - testAPI "LaunchGoogleWeb" "$inputParams" "$expectedResult" -} - -#deactivateWebKitBrowser -deactivateWebKitBrowser() -{ - inputParams='{"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}' - expectedResult='null' - testAPI "WebkitBrowserDeactivate" "$inputParams" "$expectedResult" -} - -if [ "$1" = "help" ]; then - testHelp - exit 0 -fi - -isThunderSecurityEnabled="0" -command -v tr181 >/dev/null 2>&1 -if [ $? -eq 0 ];then - echo "checking thunder security" - THUNDER_SECURITY_ENABLED=`tr181 -g Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ThunderSecurity.Enable 2>&1` - if [ $THUNDER_SECURITY_ENABLED = "true" ]; then - echo "Thunder security is enabled" - isThunderSecurityEnabled="1" - else - echo "Thunder security is disabled" - fi -else - echo "command tr181 not found " -fi - -securityToken="" -if [ $isThunderSecurityEnabled = "1" ]; then - securityToken=`WPEFrameworkSecurityUtility |awk -F\" '{print $4}'` -fi - -validate() -{ - api=$1 - expectedResult=$2 - curlOutput=$3 - inputparams=$4 - - if echo "$curlOutput" | grep -q '"result":'; then - resultParam=$(echo "$curlOutput" | awk -F'"result":' '{printf $2}' | sed "s/[{}]//g" | awk -F',' '{print $0}') - echo "Success: $resultParam" - elif echo "$curlOutput" | grep -q '"error":'; then - resultParam=$(echo "$curlOutput" | awk -F'"error":' '{printf $2}' | sed "s/[{}]//g" | awk -F',' '{print $0}') - echo "Error: $resultParam" - else - echo "Neither result nor error found." - fi - if [ "$resultParam" = "$expectedResult" ]; then - successCount=$((successCount+1)) - echo "---------------------------------------------------------------" - printf "Request: %s\n" "$inputParams" - printf "Expected: %s\n" "$expectedResult" - printf "Result: %s\n" "$resultParam" - echo "$api : Success" - echo "---------------------------------------------------------------" - return 0 - else - failuresCount=$((failuresCount+1)) - echo "---------------------------------------------------------------" - printf "Request: %s\n" "$inputParams" - printf "Expected: %s\n" "$expectedResult" - printf "Result: %s\n" "$resultParam" - echo "$api : Failed - [$resultParam] [$expectedResult]" - echo "---------------------------------------------------------------" - return 1 - fi -} - -#executes command and validates the output -testAPI() -{ - apiname=$1 - inputparams=$2 - expectedResult=$3 - - params=`echo $inputparams` - curl_command="" - if [ $isThunderSecurityEnabled = "1" ] - then - token=`echo $securityToken` - curl_command="curl -H \"Content-Type: application/json\" -H \"Authorization: Bearer $token\" -X POST --silent -d '$params' http://127.0.0.1:9998/jsonrpc" - else - curl_command="curl --silent -d '$params' http://127.0.0.1:9998/jsonrpc" - fi - curlOutput=`eval $curl_command` - validate $apiname $expectedResult "$curlOutput" $inputparams -} - -# Main logic to run the user-specified function - -if [ $# -eq 0 ];then - echo "No function name provided " - exit 1 -fi - -function_name=$1 - -#testCreateDisplayAndGetClientsForWesterosTestAppWithOutResolution -testCreateDisplay1() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams": "{\"client\":\"westerosapp\",\"displayName\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "testCreateDisplay1" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}' - expectedResult='"[\"westerosapp\"]"' - testAPI "testCreateDisplay1" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - /usr/bin/westeros_test --display westerostest & - - sleep $testAppTimeOut #15secs wait then run next test as it's westeros test app test, need to view in display - killWesterosTestApp #kill westeros test app if its running - sleep 2s -} - -#testCreateDisplayAndGetClientsForWesterosTestAppWithResolution -testCreateDisplay2() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest1\", \"displayName\": \"test1\",\"displayWidth\": 1920,\"displayHeight\": 1080,\"virtualDisplay\": false,\"virtualWidth\": 1920,\"virtualHeight\": 1080,\"topmost\": false,\"focus\": false}"}}' - expectedResult='null' - testAPI "testCreateDisplay2" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}' - expectedResult='"[\"westerostest1\"]"' - testAPI "testCreateDisplay2" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=test1 - /usr/bin/westeros_test & - - sleep $testAppTimeOut #15secs wait then run next test as it's westeros test app test, need to view in display - killWesterosTestApp #kill westeros test app if its running - sleep 2s -} - -#testCreateDisplayWithOutClient -testCreateDisplay3() -{ - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.createDisplay","params": {"displayParams": "{\"displayName\": \"test\"}"}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testCreateDisplay3" "$inputParams" "$expectedResult" -} - -#testListenersWithGenerateKey -testListeners() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\"keys\": [{\"keyCode\":70, \"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='null' - testAPI "addKeyListener" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 70, \"delay\": 5, \"modifiers\": []}]}"}}' - expectedResult='null' - testAPI "generateKeyafterAddKeyListener" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\"keys\": [{\"keyCode\":70, \"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='null' - testAPI "removeKeyListener" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut -} - -#testInterceptWithInjectKey -testIntercept1() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\"keyCode\":65,\"modifiers\": [\"shift\"],\"client\":\"googletestapp\"}"}}' - expectedResult='null' - testAPI "addKeyIntercept" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":65, "modifiers": "{\"modifiers\": [\"shift\"]}"}}' - expectedResult='null' - testAPI "injectKeyAfterAddKeyIntercept" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\"keyCode\":65,\"modifiers\": [\"shift\"],\"client\":\"googletestapp\"}"}}' - expectedResult='null' - testAPI "removeKeyIntercept" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut - -} - -#testInterceptWithGenerateKeyClientSpecified -testIntercept2() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\"keyCode\":66,\"modifiers\": [\"shift\"],\"client\":\"googletestapp\"}"}}' - expectedResult='null' - testAPI "addKeyIntercept" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 66, \"delay\": 10, \"modifiers\": [\"shift\"]}]}"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptForGoogletest" "$inputParams" "$expectedResult" - - sleep 25s - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\"keyCode\":66,\"modifiers\": [\"shift\"],\"client\":\"googletestapp\"}"}}' - expectedResult='null' - testAPI "removeKeyIntercept" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut - -} - -#testInterceptWithMutipleDisplayInjectKey -testIntercept3() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "westerostestapp" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=westerostest - /usr/bin/westeros_test & - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\"keyCode\":67,\"modifiers\": [\"shift\"],\"client\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "addKeyIntercept" "$inputParams" "$expectedResult" - - keyCodes=(67 68) - - for keyCode in "${keyCodes[@]}"; do - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":'"$keyCode"', "modifiers": "{\"modifiers\": [\"shift\"]}"}}' - testName="injectKeyAfterAddKeyInterceptKeyCode$keyCode" - expectedResult='null' - testAPI "$testName" "$inputParams" "$expectedResult" - sleep 2s - done - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\"keyCode\":67,\"modifiers\": [\"shift\"],\"client\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "removeKeyIntercept" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - killWesterosTestApp #kill westeros test app if its running - - deactivateWebKitBrowser - - sleep $testAppTimeOut - -} - -#testInterceptWithMutipleDisplayGenerateKey -testIntercept4() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "westerostestapp" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=westerostest - /usr/bin/westeros_test & - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\"keyCode\":67,\"modifiers\": [\"shift\"],\"client\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "addKeyIntercept" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 67, \"delay\": 5, \"modifiers\": [\"shift\"]},{\"keyCode\": 68, \"delay\": 5, \"modifiers\": [\"shift\"]}]}"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptWithoutClientSpecified" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\"keyCode\":67,\"modifiers\": [\"shift\"],\"client\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "removeKeyIntercept" "$inputParams" "$expectedResult" - - killWesterosTestApp #kill westeros test app if its running - - deactivateWebKitBrowser - - sleep $testAppTimeOut -} - -#testGenerateKeyWithwesterosasfocusClientSpecifiedAndNotSpecified -testGenerateKey() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "westerostestapp" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=westerostest - /usr/bin/westeros_test & - - sleep $testAppTimeOut - - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 67, \"delay\": 5, \"modifiers\": [\"shift\"]},{\"keyCode\": 68, \"delay\": 5, \"modifiers\": [\"shift\"]}]}"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptWithoutClient" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 67, \"delay\": 5, \"modifiers\": [\"shift\"]},{\"keyCode\": 68, \"delay\": 5, \"modifiers\": [\"shift\"]}]}","client": "googletestapp"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptWithClient" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - killWesterosTestApp #kill westeros test app if its running - - deactivateWebKitBrowser - - sleep $testAppTimeOut -} - -testIntercepts() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "westerostestapp" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=westerostest - /usr/bin/westeros_test & - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.addKeyIntercepts","params": {"intercepts": "{\"intercepts\": [{\"keys\": [{\"keyCode\": 75, \"modifiers\": [\"shift\"]},{\"keyCode\": 76, \"modifiers\": [\"shift\"]}],\"client\": \"googletestapp\"},{\"keys\": [{\"keyCode\": 79, \"modifiers\": []},{\"keyCode\": 80, \"modifiers\": [\"shift\"]}],\"client\": \"westerostest\"}]}"}}' - expectedResult='null' - testAPI "addKeyInterceptsForbothWesterostestandgoogletest" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 79, \"delay\": 5, \"modifiers\": []},{\"keyCode\": 76, \"delay\": 5, \"modifiers\": [\"shift\"]}]}","client": "googletestapp"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptsForGoogletestapp" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 79, \"delay\": 5, \"modifiers\": []},{\"keyCode\": 76, \"delay\": 5, \"modifiers\": [\"shift\"]}]}"}}' - expectedResult='null' - testAPI "generateKeyAfterAddKeyInterceptsWithoutClient" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\"keyCode\":79,\"modifiers\": [],\"client\":\"westerostest\"}"}}' - expectedResult='null' - testAPI "removeKeyIntercept" "$inputParams" "$expectedResult" - - killWesterosTestApp #kill westeros test app if its running - - deactivateWebKitBrowser - - sleep $testAppTimeOut -} - -#testInjectKeyAndGenerateKey -testInjectGenerateKey() -{ - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - sleep $testAppTimeOut - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":71, "modifiers": "{\"modifiers\": [\"shift\"]}"}}' - expectedResult='null' - testAPI "injectKey" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\"keys\": [{\"keyCode\": 72, \"delay\": 5, \"modifiers\": []},{\"keyCode\": 73, \"delay\": 5, \"modifiers\": [\"shift\"]}]}","client": "googletestapp"}}' - expectedResult='null' - testAPI "generateKey" "$inputParams" "$expectedResult" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut -} - -#testAddKeyListenersAndRemoveKeyListenersForFailureCases -testKeyListenersFailures() -{ - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\"keys\": [{\"keyCode\":70,\"nativeKeyCode\": 72,\"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testAddKeyListenersForFailureCasesForAddingBothKeyCodeAndNativeKeyCode" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\"keys\": [{\"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testAddKeyListenersForFailureCasesForNotHavingBothKeyCodeAndNativeKeyCode" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\"keys\": [{\"keyCode\":70,\"nativeKeyCode\": 72,\"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testRemoveKeyListenersForFailureCasesForAddingBothKeyCodeAndNativeKeyCode" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\"keys\": [{\"activate\":true, \"propagate\":false}], \"client\": \"googletestapp\"}"}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testRemoveKeyListenersForFailureCasesForNotHavingBothKeyCodeAndNativeKeyCode" "$inputParams" "$expectedResult" -} - -#testGetClientsWithOutCreateDisplay -testGetClients1() -{ - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}' - expectedResult='""' - testAPI "testGetClients2" "$inputParams" "$expectedResult" -} - -#testGetClientsWithCreateDisplay -testGetClients2() -{ - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.createDisplay","params": {"displayParams": "{\"client\": \"org.rdk.Netflix\",\"callsign\": \"org.rdk.Netflix\",\"displayName\": \"test\"}"}}' - expectedResult='null' - testAPI "testGetClients1" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}' - expectedResult='"[\"org.rdk.netflix\"]"' - testAPI "testGetClients1" "$inputParams" "$expectedResult" -} - -#Enable the feature and Set inactivity time of 1minute -testInactivity1() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.enableInactivityReporting","params":{"enable": true}}' - expectedResult='null' - testAPI "enableInactivityReporting" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.setInactivityInterval","params":{"interval":1}}' - expectedResult='null' - testAPI "setInactivityInterval" "$inputParams" "$expectedResult" - sleep 2m -} - -#Disable inactivity feature & set inactivity time of 1minute -testInactivity2() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.enableInactivityReporting","params":{"enable": false}}' - expectedResult='null' - testAPI "enableInactivityReporting" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.setInactivityInterval","params":{"interval":1}}' - expectedResult='null' - testAPI "setInactivityInterval" "$inputParams" "$expectedResult" - sleep 2m -} - -#Enable inactivity feature,wait for 1 min,when it goes nears 1min,40sec,reset the inactivity,onuserinactive should happen after a min frm current time -testInactivity3() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.enableInactivityReporting","params":{"enable": true}}' - expectedResult='null' - testAPI "enableInactivityReporting" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.setInactivityInterval","params":{"interval":1}}' - expectedResult='null' - testAPI "setInactivityInterval" "$inputParams" "$expectedResult" - - sleep 40 - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.resetInactivityTime"}}' - expectedResult='null' - testAPI "resetInactivityTime" "$inputParams" "$expectedResult" - sleep 2m -} - -#Enable inactivity feature,wait for 1 min,when it goes near 1min,say 40sec,inject key, -#onuserinactive should happen after a min frm current time" -testInactivity4() -{ - inputParams='{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"westerostest1\", \"displayName\": \"test1\",\"displayWidth\": 1920,\"displayHeight\": 1080,\"virtualDisplay\": false,\"virtualWidth\": 1920,\"virtualHeight\": 1080,\"topmost\": false,\"focus\": false}"}}' - expectedResult='null' - testAPI "testCreateDisplay2" "$inputParams" "$expectedResult" - - export XDG_RUNTIME_DIR=/tmp - export WAYLAND_DISPLAY=test1 - /usr/bin/westeros_test & - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.enableInactivityReporting","params":{"enable": true}}' - expectedResult='null' - testAPI "enableInactivityReporting" "$inputParams" "$expectedResult" - - inputParams='{"jsonrpc":"2.0","id":"3","method":"org.rdk.RDKWindowManager.setInactivityInterval","params":{"interval":1}}' - expectedResult='null' - testAPI "setInactivityInterval" "$inputParams" "$expectedResult" - - sleep 40 - - inputParams='{"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":66, "modifiers": "{\"modifiers\": [\"shift\"]}"}}' - expectedResult='null' - testAPI "injectKey" "$inputParams" "$expectedResult" - sleep 2m - killWesterosTestApp #kill westeros test app if its running - sleep 2s -} - -# Test EnableKeyRepeats -testEnableKeyRepeats() { - enable=$1 # "true" or "false" - inputParams="{\"jsonrpc\": \"2.0\", \"id\": \"1\", \"method\": \"org.rdk.RDKWindowManager.enableKeyRepeats\", \"params\": {\"enable\": $enable}}" - expectedResult='null' - testAPI "testEnableKeyRepeat_$enable" "$inputParams" "$expectedResult" -} - -# Test GetKeyRepeats Enabled state -testGetKeyRepeatsEnabled() { - echo "---- Testing GetKeyRepeatsEnabled Flow ----" - - # Disable Key Repeat - testEnableKeyRepeats "false" - - inputParams='{"jsonrpc": "2.0", "id": "3", "method": "org.rdk.RDKWindowManager.getKeyRepeatsEnabled"}' - expectedResult='false' - testAPI "testGetKeyRepeatsEnabled" "$inputParams" "$expectedResult" - - #Enable Key Repeat - testEnableKeyRepeats "true" - - inputParams='{"jsonrpc": "2.0", "id": "3", "method": "org.rdk.RDKWindowManager.getKeyRepeatsEnabled"}' - expectedResult='true' - testAPI "testGetKeyRepeatsEnabled" "$inputParams" "$expectedResult" -} - -# Test EnableInputEvents - Enable -testSetInputEventEnable() { - client_name="$1" # Accept client name as parameter - - inputParams='{ - "jsonrpc": "2.0", - "id": "5", - "method": "org.rdk.RDKWindowManager.enableInputEvents", - "params": { "clients": {"clients": ["'"$client_name"'"]}, "enable": true }}' - - expectedResult='null' - testAPI "testSetInputEventEnable" "$inputParams" "$expectedResult" -} - -# Test EnableInputEvents - Disable -testSetInputEventDisable() { - client_name="$1" # Accept client name as parameter - - inputParams='{ - "jsonrpc": "2.0", - "id": "6", - "method": "org.rdk.RDKWindowManager.enableInputEvents", - "params": { "clients": {"clients": ["'"$client_name"'"]}, "enable": false }}' - - expectedResult='null' - testAPI "testSetInputEventDisable" "$inputParams" "$expectedResult" -} - -# Test Generate Key when Input Events are Enabled (Confirm it is accepted the key) -testInputEventEnable() { - client_name="testapp" - #CreateDisplay - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams": "{\"client\":\"testapp\",\"displayName\":\"wst-webkitbrowser\"}"}}' http://127.0.0.1:9998/jsonrpc; - #webkitBrower activate - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc": "2.0","id": 5,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}' http://127.0.0.1:9998/jsonrpc ; - #Load Google Browser: - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}' http://127.0.0.1:9998/jsonrpc; - - # Enable Input Events - testSetInputEventEnable "$client_name" - - sleep $testAppTimeOut - - injectKeyInput='{"jsonrpc": "2.0", "id": "7", "method": "org.rdk.RDKWindowManager.injectKey", "params": {"keyCode":79, "modifiers": "{\"modifiers\": []}"}}' - expectedResult='null' - testAPI "testInjectKey_InputEventEnabled" "$injectKeyInput" "$expectedResult" - - sleep $testAppTimeOut - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}' http://127.0.0.1:9998/jsonrpc; - - echo "---- Confirm on the WebKitBrowser application side that the Generate key is accepted when input events are Enabled. ----" -} - -# Test Generate Key when Input Events are Disabled (Confirm it do not accept the key) -testInputEventDisable() { - client_name="testapp" - #CreateDisplay - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams": "{\"client\":\"testapp\",\"displayName\":\"wst-webkitbrowser\"}"}}' http://127.0.0.1:9998/jsonrpc; - #webkitBrower actiate - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc": "2.0","id": 5,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}' http://127.0.0.1:9998/jsonrpc ; - #Load Google Browser: - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}' http://127.0.0.1:9998/jsonrpc; - - # Disable Input Events - testSetInputEventDisable "$client_name" - sleep $testAppTimeOut - - injectKeyInput='{"jsonrpc": "2.0", "id": "7", "method": "org.rdk.RDKWindowManager.injectKey", "params": {"keyCode":79, "modifiers": "{\"modifiers\": []}"}}' - expectedResult='null' - testAPI "testInjectKey_InputEventDisabled" "$injectKeyInput" "$expectedResult" - sleep $testAppTimeOut - - curl -H "Authorization: Bearer `WPEFrameworkSecurityUtility | cut -d '"' -f 4`" --header "Content-Type: application/json" --request POST -d '{"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}' http://127.0.0.1:9998/jsonrpc; - echo "---- Confirm on the WebKitBrowser application side that the Generate key is NOT accepted when input events are disabled. ----" -} - - -# Test IgnoreKeyInputs (Enable/Disable based on argument) -testSetIgnoreKeyInputs() { - -# Check if RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is 1 and run the tests -if [ "$RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE" = "1" ]; then - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is set to 1. Running the tests.." - - state="$1" # Accept the state (true or false) as argument - - inputParams='{ - "jsonrpc": "2.0", - "id": "5", - "method": "org.rdk.RDKWindowManager.ignoreKeyInputs", - "params": {"ignore": '"$state"'} - }' - expectedResult='null' - testAPI "testIgnoreKeyInputs_$state" "$inputParams" "$expectedResult" -else - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is NOT set. Skipping the tests." -fi -} - -# Test Key Press when Ignore Key input is Enabled (Confirm it do not accept the key) -testIgnoreKeyInputsEnable() { - -# Check if RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is 1 and run the tests -if [ "$RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE" = "1" ]; then - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is set to 1. Running the tests.." - - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - - echo "---- Testing Inject Key Flow when Input Events are Disabled ----" - # Enable IgnoreKey Input - testSetIgnoreKeyInputs "true" - - sleep $testAppTimeOut - - # Verify that key is NOT displayed on the screen - echo "---- Confirm on the WebKitBrowser application side that the physical key press [remote key press] is NOT accepted when IgnoreKey Inputs Disbled. ----" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut -else - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is NOT set. Skipping the tests." -fi -} - -# Test Key press when Ignore Key input is Disabled (Confirm it accept the key) -testIgnoreKeyInputsDisable() { - -# Check if RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is 1 and run the tests -if [ "$RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE" = "1" ]; then - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is set to 1. Running the tests.." - - createDisplayAndLaunchGoogleBrowser #Launch the GoogleBrowser with webkitBrowser - echo "---- Testing Inject Key Flow when Input Events are Disabled ----" - # Disable Ignore KeyInput - testSetIgnoreKeyInputs "false" - - sleep $testAppTimeOut - - # Verify that the key is displayed on the screen - - echo "---- Confirm on the WebKitBrowser application side that the physical key press [remote key press] is accepted when IgnoreKey Inputs Disbled. ----" - - sleep $testAppTimeOut - - deactivateWebKitBrowser - - sleep $testAppTimeOut -else - echo "Environment variable RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE is NOT set. Skipping the tests." -fi - -} - - -#Test KeyRepeatConfig enable/disable -testSetKeyRepeatConfig() { - enabled="$1" # Accept 'enabled' state (true/false) as argument - inputParams='{"jsonrpc": "2.0", "id": "1", "method": "org.rdk.RDKWindowManager.keyRepeatConfig", "params": {"input": "default", "keyConfig": {"enabled": '"$enabled"', "initialDelay": 500, "repeatInterval": 100}}}' - expectedResult='null' - testAPI "testSetKeyRepeatConfig" "$inputParams" "$expectedResult" -} - - -#Test KeyRepeatConfig Unsupported input [any input other than "default"/"keyboard" considered as unsupported] -testKeyRepeatConfigUnsupportedInput() { - inputParams='{"jsonrpc": "2.0", "id": "5", "method": "org.rdk.RDKWindowManager.keyRepeatConfig", "params": {"input": "mouse", "keyConfig": {"enabled": true, "initialDelay": 500, "repeatInterval": 100}}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testKeyRepeatConfig_UnsupportedInput" "$inputParams" "$expectedResult" -} - -#Test misisng enabled param -testKeyRepeatConfigMissingEnabled() { - inputParams='{"jsonrpc": "2.0", "id": "6", "method": "org.rdk.RDKWindowManager.keyRepeatConfig", "params": {"input": "default", "keyConfig": {"initialDelay": 500, "repeatInterval": 100}}}' - expectedResult='"code":1,"message":"ERROR_GENERAL"' - testAPI "testKeyRepeatConfig_MissingEnabled" "$inputParams" "$expectedResult" -} - -#testAll -testAll() -{ - echo "---------------------------------------------------------------" - echo "Running testCreateDisplay1" - testCreateDisplay1 - echo "wait for 10secs and start next test" - echo "Completed testCreateDisplay1" - echo "---------------------------------------------------------------" - echo "Running testCreateDisplay2" - testCreateDisplay2 - echo "Completed testCreateDisplay2" - echo "---------------------------------------------------------------" - echo "Running testCreateDisplay3" - testCreateDisplay3 - echo "Completed testCreateDisplay3" - echo "---------------------------------------------------------------" - echo "Running testListeners" - testListeners - echo "Completed testListeners" - echo "---------------------------------------------------------------" - echo "Running testIntercept1" - testIntercept1 - echo "Completed testIntercept1" - echo "---------------------------------------------------------------" - echo "Running testIntercept2" - testIntercept2 - echo "Completed testIntercept2" - echo "---------------------------------------------------------------" - echo "Running testIntercept3" - testIntercept3 - echo "Completed testIntercept3" - echo "---------------------------------------------------------------" - echo "Running testIntercept4" - testIntercept4 - echo "Completed testIntercept4" - echo "---------------------------------------------------------------" - echo "Running testGenerateKey" - testGenerateKey - echo "Completed testGenerateKey" - echo "---------------------------------------------------------------" - echo "Running testIntercepts" - testIntercepts - echo "Completed testIntercepts" - echo "---------------------------------------------------------------" - echo "Running testInjectGenerateKey" - testInjectGenerateKey - echo "Completed testInjectGenerateKey" - echo "---------------------------------------------------------------" - echo "Running testKeyListenersFailures" - testKeyListenersFailures - echo "Completed testKeyListenersFailures" - echo "---------------------------------------------------------------" - echo "Running testInactivity1" - testInactivity1 - echo "Completed testInactivity1" - echo "---------------------------------------------------------------" - echo "Running testInactivity2" - testInactivity2 - echo "Completed testInactivity2" - echo "---------------------------------------------------------------" - echo "Running testInactivity3" - testInactivity3 - echo "Completed testInactivity3" - echo "---------------------------------------------------------------" - echo "Running testInactivity4" - testInactivity4 - echo "Completed testInactivity4" - echo "---------------------------------------------------------------" - echo "Running testGetClients1" - testGetClients1 - echo "Completed testGetClients1" - echo "---------------------------------------------------------------" - echo "Running testGetClients2" - testGetClients2 - echo "Completed testGetClients2" - echo "---------------------------------------------------------------" - echo "Running testGetKeyRepeatsEnabled" - testGetKeyRepeatsEnabled - echo "Completed testGetKeyRepeatsEnabled" - echo "---------------------------------------------------------------" - echo "Running testInputEventEnable" - testInputEventEnable - echo "Completed testInputEventEnable" - echo "---------------------------------------------------------------" - echo "Running testInputEventDisable" - testInputEventDisable - echo "Completed testInputEventDisable" - echo "---------------------------------------------------------------" - echo "Running testIgnoreKeyInputsEnable" - testIgnoreKeyInputsEnable - echo "Completed testIgnoreKeyInputsEnable" - echo "---------------------------------------------------------------" - echo "Running testIgnoreKeyInputsDisable" - testIgnoreKeyInputsDisable - echo "Completed testIgnoreKeyInputsDisable" - echo "---------------------------------------------------------------" - echo "Running testKeyRepeatConfigUnsupportedInput" - testKeyRepeatConfigUnsupportedInput - echo "Completed testKeyRepeatConfigUnsupportedInput" - echo "---------------------------------------------------------------" - echo "Running testKeyRepeatConfigMissingEnabled" - testKeyRepeatConfigMissingEnabled - echo "Completed testKeyRepeatConfigMissingEnabled" - echo "---------------------------------------------------------------" -} - -invoke_function() { - case $function_name in - testCreateDisplay1) - testCreateDisplay1 - ;; - testCreateDisplay2) - testCreateDisplay2 - ;; - testCreateDisplay3) - testCreateDisplay3 - ;; - testInactivity1) - testInactivity1 - ;; - testInactivity2) - testInactivity2 - ;; - testInactivity3) - testInactivity3 - ;; - testInactivity4) - testInactivity4 - ;; - testGetClients1) - testGetClients1 - ;; - testGetClients2) - testGetClients2 - ;; - testListeners) - testListeners - ;; - testIntercept1) - testIntercept1 - ;; - testIntercept2) - testIntercept2 - ;; - testIntercept3) - testIntercept3 - ;; - testIntercept4) - testIntercept4 - ;; - testGenerateKey) - testGenerateKey - ;; - testIntercepts) - testIntercepts - ;; - testInjectGenerateKey) - testInjectGenerateKey - ;; - testKeyListenersFailures) - testKeyListenersFailures - ;; - testGetKeyRepeatsEnabled) - testGetKeyRepeatsEnabled - ;; - testInputEventEnable) - testInputEventEnable - ;; - testInputEventDisable) - testInputEventDisable - ;; - testIgnoreKeyInputsEnable) - testIgnoreKeyInputsEnable - ;; - testIgnoreKeyInputsDisable) - testIgnoreKeyInputsDisable - ;; - testKeyRepeatConfigUnsupportedInput) - testKeyRepeatConfigUnsupportedInput - ;; - testKeyRepeatConfigMissingEnabled) - testKeyRepeatConfigMissingEnabled - ;; - testAll) - testAll - ;; - - *) - echo "Function '$function_name' not found." - ;; - esac -} - -# Call the invoke_function to start the script -invoke_function - -totalCases=$(expr $successCount + $failuresCount) - -echo "---------------------------------------------------------------" -echo "Total Test Cases - $totalCases" -echo "Success Test Count - $successCount" -echo "Failed Test Count - $failuresCount" -echo "---------------------------------------------------------------" - -if [ $failuresCount -eq 0 ] -then - exit 0 -else - exit 1 -fi diff --git a/RDKWindowManager/test/README.md b/RDKWindowManager/test/README.md deleted file mode 100755 index cdef189..0000000 --- a/RDKWindowManager/test/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# RDKWindowManager Testing Documentation - -## Test using Script -A new script, `RDKWMJsonL3Test.sh`, has been added for testing RDKWindowManager plugin methods using JSON-RPC curl commands. - -Only a few test cases have been added so far. If you want to verify more test cases, you can use the curl command directly in the terminal for testing. For example: - -### Fresh Boot (Recommended) -To run the test-related test cases or the `testAll` test cases using the script, you should stop the sky service first and then activate the plugin again using the curl command. - -### Step 1: Stop the Sky Service -Run the following commands **twice** to stop the sky service: - -systemctl stop sky-appsservice -systemctl stop sky-appsservice - - -### Step 2: Activate the RDKWindowManager Plugin -Activate the plugin using the following curl command: - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc": "2.0", "id": 42, "method": "Controller.1.activate", "params": {"callsign": "org.rdk.RDKWindowManager"}}' http://127.0.0.1:9998/jsonrpc - - -### Step 3: Ensure Plugin Activation -Verify that the RDKWindowManager Plugin has been activated using the verbose curl command: - -curl --verbose http://127.0.0.1:9998/Service/Controller - - -### Step 4: Execute Test Commands -Now, execute the commands listed in the table below. - -> **Note:** A test case may fail if there are conflicts with displays or if the display is already pre-created with the same name. If this happens, it is recommended to reboot the device and try running the test again. - -| Si.No | TestCase | Command |  Test Details | Expected Output | Remarks | -| ----- | ------------------------------- | -------------------------------------------- | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| 1 | testCreateDisplay1 | RDKWMJsonL3Test.sh testCreateDisplay1 | 1\. Without resolution, it will invoke the createDisplay function with the Westerosapp client.
2\. It will invoke the getClients function to verify that the westerostest client is present.
3\. The westerostest client will connect to the westeros_test app, which will then launch.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes
From Logs: createDisplay and getClients methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams": "{\\"client\\":\\"westerosapp\\",\\"displayName\\":\\"westerostest\\"}"}}
Expected: null
Result: null
testCreateDisplay1 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}
Expected: "[\\"westerosapp\\"]"
Result: "[\\"westerosapp\\"]"
testCreateDisplay1 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 2
Success Test Count - 2
Failed Test Count - 0
\--------------------------------------------------------------- | | -| 2 | testCreateDisplay2 | RDKWMJsonL3Test.sh testCreateDisplay2 | 1\. With given resolution, it will invoke the createDisplay function with the Westerosapp client.
2\. It will invoke the getClients function to verify that the westerostest client is present.
3\. The westerostest client will connect to the westeros_test app, which will then launch.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes
From Logs: createDisplay and getClients methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"westerostest1\\", \\"displayName\\": \\"test1\\",\\"displayWidth\\": 1920,\\"displayHeight\\": 1080,\\"virtualDisplay\\": false,\\"virtualWidth\\": 1920,\\"virtualHeight\\": 1080,\\"topmost\\": false,\\"focus\\": false}"}}
Expected: null
Result: null
testCreateDisplay2 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}
Expected: "[\\"westerostest1\\"]"
Result: "[\\"westerostest1\\"]"
testCreateDisplay2 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 2
Success Test Count - 2
Failed Test Count - 0
\--------------------------------------------------------------- | | -| 3 | testCreateDisplay3 | RDKWMJsonL3Test.sh testCreateDisplay3 | 1\. It will invoke the createDisplay function without any client.
2\. Expecting ERROR_GENERAL in error code | On Screen Display - No
From Logs: createDisplay request will call and get error code
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.createDisplay","params": {"displayParams": "{\\"displayName\\": \\"test\\"}"}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testCreateDisplay3 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 1
Success Test Count - 1
Failed Test Count - 0
\--------------------------------------------------------------- | | -| 4 | testListeners | RDKWMJsonL3Test.sh testListeners | 1\. With default resolution,invoke the createDisplay function with the google browser client.
2\. AddKeyListener with keyCode 70 with client googletestapp.
3\. GenerateKey for keyCode 70 without client.
4\.RemoveKeyListener for keyCode 70 with client googletestapp.
5\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, GoogleBrowser will launch and f should be seen on google screen if focus is googleBrowser
logs: rdkwindowmanager_focus create: setting focus of first application created googletestapp
From Logs: methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"googletestapp\\", \\"displayName\\": \\"wst-webkitbrowser\\"}"}}
Expected: null
Result: null
CreateDisplayForGoogle : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserActivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
LaunchGoogleWeb : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"keyCode\\":70, \\"activate\\":true, \\"propagate\\":false}], \\"client\\": \\"googletestapp\\"}"}}
Expected: null
Result: null
addKeyListener : Success
---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 70, \\"delay\\": 5, \\"modifiers\\": []}]}"}}
Expected: null
Result: null
generateKeyafterAddKeyListener : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"keyCode\":70, \\"activate\\":true, \\"propagate\\":false}],\\"client\\": \\"googletestapp\\"}"}}
Expected: null
Result: null
removeKeyListener : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 7
Success Test Count - 7
Failed Test Count - 0
\---------------------------------------------------------------| |-------- -| 5 | testIntercept1 | RDKWMJsonL3Test.sh testIntercept1 | 1\. With default resolution,invoke the createDisplay function with the google browser client.
2\. AddKeyIntercept with keyCode 65 with shift with client googletestapp.
3\. InjectKey for keyCode 65 with Modifers shift.
4\.RemoveKeyIntercept with keyCode 65 with shift,client googletestapp.
5\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, GoogleBrowser will launch and A should be seen in the screen as key A is intercepted with googleclient
logs: injectKey keyCode 65 flags 8,
rdkwindowmanager_focus key intercepted: 1 focused client: googletestapp
From Logs: methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"googletestapp\\", \\"displayName\\": \\"wst-webkitbrowser\\"}"}}
Expected: null
Result: null
CreateDisplayForGoogle : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserActivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
LaunchGoogleWeb : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\\"keyCode\\":65,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"googletestapp\\"}"}}
Expected: null
Result: null
addKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":65, "modifiers": "{\\"modifiers\": [\\"shift\\"]}"}}
Expected: null
Result: null
injectKeyAfterAddKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\\"keyCode\\":65,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"googletestapp\\"}"}}
Expected: null
Result: null
removeKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 7
Success Test Count - 7
Failed Test Count - 0
\---------------------------------------------------------------| |----- -| 6 | testIntercept2 | RDKWMJsonL3Test.sh testIntercept2 | 1\. With default resolution,invoke the createDisplay function with the google browser client.
2\. AddKeyIntercept with keyCode 66 with client googletestapp.
3\.GenerateKey for keyCode 66 with Modifers shift ,with client googletestapp.
4\.RemoveKeyIntercept with keyCode 66 with modifier shift, client googletestapp.
5\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, GoogleBrowser will launch and B should be seen on the screen as key B is intercepted with googleclient
From Logs: methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"googletestapp\\", \\"displayName\\":\\"wst-webkitbrowser\\"}"}}
Expected: null
Result: null
testCreateDisplayForGoogle : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
testWebkitBrowserActivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
testLaunchGoogleWeb : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\\"keyCode\\":66,\\"modifiers\\":[\\"shift\\"],\\"client\\":\\"googletestapp\\"}"}}
Expected: null
Result: null
testAddKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\":[{\\"keyCode\\":66,\\"delay\\":10,\\"modifiers\\":[\\"shift\\"]}]}"}}
Expected: null
Result: null
testGenerateKeyAfterAddKeyIntercept : Success
\---------------------------------------------------------------
\-------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\\"keyCode\\":66,\\"modifiers\\":[\\"shift\\"],\\"client\\":\\"googletestapp\\"}"}}
Expected: null
Result: null
testRemoveKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
testWebkitBrowserDeactivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 7
Success Test Count - 7
Failed Test Count - 0
\---------------------------------------------------------------| |--------------- -| 7 | testIntercept3 | RDKWMJsonL3Test.sh testIntercept3 | 1\. with default Resolution,invoke the createDisplay function and launch the google browser client.
2\. Create and Launch westeros test.
3\. AddKeyIntercept with keyCode 67 with modifer shift , client westerostest.
4\.InjectKey for keyCode 67 and 68 with Modifers shift.
5\.RemoveKeyIntercept with keyCode 67 with modifier shift, client westerostest.
6\.kill westerostest.
7\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, GoogleBrowser and westeros client is launched injectKey 67 is not seen in googlescreen as it is intercepted and 68 is seen if focus is googlebrowser
From Logs: Google Browser request and response same as above,other methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"westerostest\\"}"}}
Expected: null
Result: null
westerostestapp : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\\"keyCode\\":67,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"westerostest\\"}"}}
Expected: null
Result: null
addKeyIntercept :Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":67, "modifiers": "{\\"modifiers\": [\\"shift\\"]}"}}
Expected: null
Result: null
injectKeyAfterAddKeyInterceptKeyCode67 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":68, "modifiers": "{\\"modifiers\\": [\\"shift\\"]}"}}
Expected: null
Result: null
injectKeyAfterAddKeyInterceptKeyCode68 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\\"keyCode\\":67,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"westerostest\\"}"}}
Expected: null
Result: null
removeKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
./RDKWMJsonL3Test.sh: line 155: 1298 Terminated /usr/bin//westeros_test
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 9
Success Test Count - 9
Failed Test Count - 0
\---------------------------------------------------------------| | -| 8 | testIntercept4 | RDKWMJsonL3Test.sh testIntercept4 | 1\. with default Resolution,invoke the createDisplay function and launch the google browser client.
2\. Create and Launch westeros test.
3\. AddKeyIntercept with keyCode 67 with modifer shift , client westerostest.
4\.GenerateKey for keyCode 67 with Modifers shift.
5\.RemoveKeyIntercept with keyCode 67 with modifier shift, client westerostest
6\.kill westerostest.
7\.Deactivate webkitBrowser

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, Google Browser and westeros client is launched During GenerateKey C is not seen on the google screen as it is intercepted and D can be seen as it is not intercepted ,
logs: generateKey keyCode 67 flags 8,
generateKey with duration keyCode 67 flags 8
rdkwindowmanager_focus key intercepted: 1 focused client: googletestapp
From Logs: Google Browser request and response same as above,other methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"westerostest\\"}"}}
Expected: null
Result: null
westerostestapp : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.addKeyIntercept", "params":{"intercept":"{\\"keyCode\\":67,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"westerostest\\"}"}}
Expected: null
Result: null
addKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 67, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]},{\\"keyCode\\": 68, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]}]}"}}
Expected: null
Result: null
generateKeyAfterAddKeyInterceptWithoutClientSpecified : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\\"keyCode\\":67,\\"modifiers\\": [\\"shift\\"],\\"client\\":\\"westerostest\\"}"}}
Expected: null
Result: null
removeKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
RDKWMJsonL3Test.sh: line 155: 8965 Terminated /usr/bin//westeros_test
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
Total Test Cases - 8
Success Test Count - 8
Failed Test Count - 0
\---------------------------------------------------------------| | -| 9 | testGenerateKey | RDKWMJsonL3Test.sh testGenerateKey | 1\. create and launch westeros test client.
2\. with default Resolution,invoke the createDisplay function and launch the google browser client.
3\.Generate key with keyCode 67 and 68 with modifer shift ,without client .
4\.GenerateKey for keyCode 67 and 68 with Modifers shift,with client googletestapp.
6\.kill westerostest.
7\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes Westeros client and Google Browser will launch , first generateKey CD is not seen as focus is on westeros and 2nd generateKeywithClient on the screen CD is seen
From Logs: methods request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"westerostest\\"}"}}
Expected: null
Result: null
westerostestapp : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.generateKey", "params":{"keys": "{\"keys\": [{\"keyCode\": 67, \"delay\": 5, \"modifiers\": [\"shift\"]},{\"keyCode\": 68, \"delay\": 5, \"modifiers\": [\"shift\"]}]}"}}'
Expected: null
Result: null
generateKeyWithoutClient : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 67, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]},{\\"keyCode\\": 68, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]}]}","client": "googletestapp"}}
Expected: null
Result: null
generateKeytWithClient : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
RDKWMJsonL3Test.sh: line 155: 8965 Terminated /usr/bin//westeros_test
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
Total Test Cases - 7
Success Test Count - 7
Failed Test Count - 0
\---------------------------------------------------------------| | -| 10 | testIntercepts | RDKWMJsonL3Test.sh testIntercepts | 1\. with default Resolution,invoke the createDisplay function and launch the google browser client.
2\. create and Launch westerostest.
3\. AddKeyIntercepts for keyCode 75 and 76 with shift,client googletestapp & 80 with shift and 79 with no modifiers,client westerostest.
4\.GenerateKey for keyCode 79 with no modifiers and 76 with shift, client googletestapp.
5\.GenerateKey for keyCode 79 with no modifiers and 76 with shift, without client.
6\.RemoveKeyIntercept with keyCode 79 with modifier shift, client westerostest.
7\.kill westerostest.
8\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes GoogleBrowser and Westeros is launched , 1st GenerateKey of o and L will be seen as client is specifed and 2nd generateKey as o is intercepted not seen and only L is seen
From Logs: Google Browser request and response same as above , other method request & response .

---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\\"callsign\\":\\"westerostest\\"}"}}
Expected: null
Result: null
westerostestapp : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.addKeyIntercepts","params": {"intercepts": "{\"intercepts\": [{\"keys\": [{\"keyCode\": 75, \"modifiers\": [\"shift\"]},{\"keyCode\": 76, \"modifiers\": [\"shift\"]}],\"client\": \"googletestapp\"},{\"keys\": [{\"keyCode\": 79, \"modifiers\": []},{\"keyCode\": 80, \"modifiers\": [\"shift\"]}],\"client\": \"westerostest\"}]}"}}
Expected: null
Result: null
addKeyInterceptsForbothWesterostestandgoogletest : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 79, \\"delay\\": 5, \\"modifiers\\": []},{\\"keyCode\\": 76, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]}]}","client": "googletestapp"}}
Expected: null
Result: null
generateKeyAfterAddKeyInterceptsForGoogletestapp : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 79, \\"delay\\": 5, \\"modifiers\\": []},{\\"keyCode\\": 76, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]}]}"}}
Expected: null
Result: null
generateKeyAfterAddKeyInterceptsWithoutClient : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.removeKeyIntercept", "params":{"intercept":"{\\"keyCode\\":79,\\"modifiers\\": [],\\"client\\":\\"westerostest\\"}"}}
Expected: null
Result: null
removeKeyIntercept : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
/RDKWMJsonL3Test.sh: line 155: 10756 Terminated /usr/bin//westeros_test
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
---------------------------------------------------------------Total Test Cases - 9
Success Test Count - 9
Failed Test Count - 0
\---------------------------------------------------------------| | -| 11 | testInjectGenerateKey | RDKWMJsonL3Test.sh testInjectGenerateKey | 1\. with default Resolution,invoke the createDisplay function and launch the google browser client.
2\. injectKey for keyCode 71.
3\.GenerateKey for keyCode 72 and 73 with shift,client googletestapp.
4\.Deactivate webkitBrowser.

Note:

Before starting the test, Stop the sky service using systemctl command | On Screen Display - Yes, Google Browser is launched ,injectKey G is seen if focus is googlebrowser and generateKey h and I should be seen as client is specified
From Logs: methods for request and response

\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"googletestapp\", \"displayName\": \"wst-webkitbrowser\"}"}}
Expected: null
Result: null
CreateDisplayForGoogle : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserActivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
LaunchGoogleWeb : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.injectKey","params": {"keyCode":71, "modifiers": "{\\"modifiers\\": [\\"shift\\"]}"}}
Expected: null
Result: null
injectKey : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "3","method": "org.rdk.RDKWindowManager.generateKey","params": {"keys": "{\\"keys\\": [{\\"keyCode\\": 72, \\"delay\\": 5, \\"modifiers\\": []},{\\"keyCode\\": 73, \\"delay\\": 5, \\"modifiers\\": [\\"shift\\"]}]}","client": "googletestapp"}}
Expected: null
Result: null
generateKey : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 6
Success Test Count - 6
Failed Test Count - 0
\---------------------------------------------------------------| | -| 12 | testKeyListenersFailures | RDKWMJsonL3Test.sh testKeyListenersFailures | 1\. AddKeyListener with both keyCode and NativeKeyCode present.
2\. Expecting ERROR_GENERAL in error code.
3\.AddKeyListener without both keyCode and NativeKeyCode.
4\.Expecting ERROR_GENERAL in error code.
5\.RemoveKeyListener with both keyCode and NativeKeyCode.
6\.Expecting ERROR_GENERAL in error code.
7\.RemoveKeyListener without both keyCode and NativeKeyCode.
8\.Expecting ERROR_GENERAL in error code.| On Screen Display - Yes
From Logs: methods for request and response

\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"keyCode\\":70,\\"nativeKeyCode\\": 72,\\"activate\\":true, \\"propagate\\":false}], \\"client\\": \\"googletestapp\\"}"}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testAddKeyListenersForFailureCasesForAddingBothKeyCodeAndNativeKeyCode : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.addKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"activate\\":true, \\"propagate\\":false}], \\"client\\": \\"googletestapp\\"}"}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testAddKeyListenersForFailureCasesForNotHavingBothKeyCodeAndNativeKeyCode : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"keyCode\\":70,\\"nativeKeyCode\\": 72,\\"activate\\":true, \\"propagate\\":false}], \\"client\\": \\"googletestapp\\"}"}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testRemoveKeyListenersForFailureCasesForAddingBothKeyCodeAndNativeKeyCode : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": "4","method": "org.rdk.RDKWindowManager.removeKeyListener","params": {"keyListeners": "{\\"keys\\": [{\\"activate\\":true, \\"propagate\\":false}], \\"client\\": \\"googletestapp\\"}"}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testRemoveKeyListenersForFailureCasesForNotHavingBothKeyCodeAndNativeKeyCode : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 4
Success Test Count - 4
Failed Test Count - 0
\---------------------------------------------------------------| | -| 13 | testInactivity1 | RDKWMJsonL3Test.sh testInactivity1 | 1\. Enable the inactivity reporting feature.
2\. Set inactivity time of 1 minute. | On Screen Display - No
Sample logs that needs to be observed(time may differ depending upon the current time)
\---------------------------------------------
i)EnableInactivityReporting: EnableInactivityReporting Entered
ii)setInactivityInterval: RDKWindowManager setInactivity for Interval:1
iii)Callback should be invoked for every minute
onUserInactive: RDKWindowManager onUserInactive event received minutes: 1.346539
onUserInactive: RDKWindowManager onUserInactive event received minutes: 2.346863
| | -| 14 | testInactivity2 | RDKWMJsonL3Test.sh testInactivity2 | 1\. Disable the inactivity reporting feature.
2\. Set inactivity time of 1 minute. | On Screen Display - No
Sample logs that needs to be observed(time may differ depending upon the current time)
\---------------------------------------------
i)EnableInactivityReporting: EnableInactivityReporting Entered
ii)setInactivityInterval: RDKWindowManager setInactivity for Interval:1
iii)Callback should not be invoked as the feature is disabled
i.e ,Should not be seeing below log:
onUserInactive: RDKWindowManager onUserInactive event received minutes: <>
| | -| 15 | testInactivity3 | RDKWMJsonL3Test.sh testInactivity3 | 1\. Enable the inactivity reporting feature.
2\. Set inactivity time of 1 minute.
3\.Wait for 40seconds and then reset | On Screen Display - No
Sample logs that needs to be observed(time may differ depending upon the current time)
\---------------------------------------------
i)EnableInactivityReporting: EnableInactivityReporting Entered
ii)onUserInactive: RDKWindowManager onUserInactive event received minutes: 7.305942 
iii)setInactivityInterval: RDKWindowManager setInactivity for Interval:1
iv)Callback will be incoming now:
onUserInactive: RDKWindowManager onUserInactive event received minutes: 7.306774
v)resetInactivityTime: RDKWindowManager inactivity time reset
vi)The inactive timer will be reset and it will restart counting amin offset with current time
i.e,
Dispatch: RDKWindowManager Dispatch OnUserInactivity minutes: 1.000350
Dispatch: RDKWindowManager Dispatch OnUserInactivity minutes: 2.000690 | | -| 16 | testInactivity4 | RDKWMJsonL3Test.sh testInactivity4 | 1\. Ran westeros test application.
2\. Enable the inactivity reporting feature.
3\.Set inactivity time of 1min and wait for 40secs
4\. Inject key | On Screen Display - Westeros app will be running
Sample logs that needs to be observed(time may differ depending upon the current time)
\---------------------------------------------
i)EnableInactivityReporting: EnableInactivityReporting Entered
ii)setInactivityInterval: RDKWindowManager setInactivity for Interval:1 
iii)Callback will be incoming now for every minute:
Dispatch: RDKWindowManager Dispatch OnUserInactivity minutes: 3.70336
iv)InjectKey: modifiers :shift
v)The inactive timer will be reset and it will restart counting amin offset with current time
i.e,
Dispatch: RDKWindowManager Dispatch OnUserInactivity minutes: 1.000240
Dispatch: RDKWindowManager Dispatch OnUserInactivity minutes: 2.000720
| | -| 17 | testGetClients1 | RDKWMJsonL3Test.sh testGetClients1 | 1\. It will invoke the getClients function without calling the createDisplay and ensure no clients are present
Note: This test was run without performing any createDisplay. | On Screen Display - No
From Logs: createDisplay and getClients methods request and response
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}
Expected: ""
Result: ""
testGetClients2 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 1
Success Test Count - 1
Failed Test Count - 0
\--------------------------------------------------------------- | | -| 18 | testGetClients2 | RDKWMJsonL3Test.sh testGetClients2 | 1\. It will invoke the createDisplay function with client only.
2\. It will invoke the getClients function to verify that the client is present. | On Screen Display - No
From Logs: createDisplay and getClients methods request and response
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.createDisplay","params": {"displayParams": "{\\"client\\": \\"org.rdk.Netflix\\",\\"callsign\\": \\"org.rdk.Netflix\\",\\"displayName\\": \\"test\\"}"}}
Expected: null
Result: null
testGetClients1 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 42,"method": "org.rdk.RDKWindowManager.getClients"}
Expected: "[\\"org.rdk.netflix\\"]"
Result: "[\\"org.rdk.netflix\\"]"
testGetClients1 : Success
\---------------------------------------------------------------
\---------------------------------------------------------------
Total Test Cases - 2
Success Test Count - 2
Failed Test Count - 0
\-------------------------------------------------------------- -| 19 | testGetKeyRepeatsEnabled | RDKWMJsonL3Test. testGetKeyRepeatsEnabled | 1. Call the testEnableKeyRepeats function to disable the key repeat feature.
2.Invoke the org.rdk.RDKWindowManager.getKeyRepeatsEnabled method
3.Verify that the response is false, indicating that key repeats are disabled.
4.Call the testEnableKeyRepeats function to enable the key repeat feature
5.Invoke the org.rdk.RDKWindowManager.getKeyRepeatsEnabled method
6.Verify that the response is true, confirming that key repeats are enabled.| On Screen Display - No
From Logs: getKeyRepeatsEnabled methods request and response
-----------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "1", "method": "org.rdk.RDKWindowManager.enableKeyRepeats", "params": {"enable": false}}
Expected: null
Result: null
testEnableKeyRepeat_setKeyRepeatDisable : Success
---------------------------------------------------------------
---------------------------------------------------------------
---- Testing GetKeyRepeatsEnabled Flow ----
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "1", "method": "org.rdk.RDKWindowManager.enableKeyRepeats", "params": {"enable": false}}
Expected: null
Result: null
testEnableKeyRepeat_false : Success
---------------------------------------------------------------
Success: false
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "3", "method": "org.rdk.RDKWindowManager.getKeyRepeatsEnabled"}
Expected: false
Result: false
testGetKeyRepeatsEnabled : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "1", "method": "org.rdk.RDKWindowManager.enableKeyRepeats", "params": {"enable": true}}
Expected: null
Result: null
testEnableKeyRepeat_true : Success
---------------------------------------------------------------
Success: true
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "3", "method": "org.rdk.RDKWindowManager.getKeyRepeatsEnabled"}
Expected: true
Result: true
testGetKeyRepeatsEnabled : Success
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 4
Success Test Count - 4
Failed Test Count - 0
--------------------------------------------------------------- -|20 | testInputEventEnable | RDKWMJsonL3Test.sh testInputEventEnable| 1.create a display using the createDisplay API
2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate
3.Load the Google homepage in the WebKitBrowser
4. Enable input events for the testapp client by calling the testSetInputEventEnable function.
5.Attempt to inject a key using the injectKey API
6.Verify that the response is null
7.Confirm that the key injection is accepted on the WebKitBrowser application side when input events are Enabled | On Screen Display - Confirm that the key injection is accepted on the WebKitBrowser application side
From Logs: enableInputEvent method request and response
\---------------------------------------------------------------
--------------------------------------------------------------
---------------------------------------------------------------
Request:
"jsonrpc": "2.0",
"id": "5",
"method": "org.rdk.RDKWindowManager.enableInputEvents",
"params": { "clients": {"clients": ["testapp"]}, { "enable": true }}
Expected: null
Result: null
testSetInputEventEnable : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request:
"jsonrpc": "2.0",
"id": "5",
"method": "org.rdk.RDKWindowManager.enableInputEvents",
"params": { "clients": {"clients": ["testapp"]}, {
enable": true }}
Expected: null
Result: null
testInjectKey_InputEventEnabled : Success
---------------------------------------------------------------
{"jsonrpc":"2.0","id":4,"result":null}---- Confirm on the WebKitBrowser application side that the Generate key is accepted when input events are Enabled. ----
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 2
Success Test Count - 2
Failed Test Count - 0
---------------------------------------------------------------
-|21 | testInputEventDisable | RDKWMJsonL3Test.sh testInputEventDisable| 1.create a display using the createDisplay API
2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate
3.Load the Google homepage in the WebKitBrowser
4. Disable input events for the testapp client by calling the testSetInputEventEnable function.
5.Attempt to inject a key using the injectKey API
6.Verify that the response is null
7.Confirm that the key injection is NOT accepted on the WebKitBrowser application side when input events are Disabled | On Screen Display - Confirm that the key injection is NOT accepted on the WebKitBrowser application side
From Logs: enableInputEvent method request and response
\---------------------------------------------------------------
--------------------------------------------------------------
Request: {
"jsonrpc": "2.0",
"id": "6",
"method": "org.rdk.RDKWindowManager.enableInputEvents", "params": { "clients": {"clients": ["testapp"]}, "enable": false }}
Expected: null
Result: null
testEnableInputEvents_setInputEventDisable : Success
---------------------------------------------------------------
---------------------------------------------------------------
Request: {
"jsonrpc": "2.0",
"id": "6",
"method": "org.rdk.RDKWindowManager.enableInputEvents", "params": { "clients": {"clients": ["testapp"]}, "enable": false }}
Expected: null
Result: null
testInjectKey_InputEventDisabled : Success
---------------------------------------------------------------
---------------------------------------------------------------{"jsonrpc":"2.0","id":4,"result":null}---- Confirm on the WebKitBrowser application side that the Generate key is NOT accepted when input events are disabled. ----
---------------------------------------------------------------
Total Test Cases - 2
Success Test Count - 2
Failed Test Count - 0 -|22 | testIgnoreKeyInputsEnable |RDKWMJsonL3Test.sh testIgnoreKeyInputsEnable |Prerequisites:The RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE feature must be enabled (set to 1) for this function to execute.
1.create a display using the createDisplay API
2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate
3.Load the Google homepage in the WebKitBrowser
4. Enable the ignoreKeyInputs feature by invoking the ignoreKeyInputs API with the enabled parameter set to true.
5.Verify that the response is null.
6.Attempt to press a key using the Remote Controller".
7.Confirm that the key injection is not accepted on the application side when key inputs are ignored.| On Screen Display - Confirm that the key injection is not accepted on the WebKitBrowser application side
From Logs: ignoreKeyInputs method request and response
\---------------------------------------------------------------
---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"googletestapp\", \"displayName\": \"wst-webkitbrowser\"}"}}
Expected: null
Result: null
CreateDisplayForGoogle : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserActivate : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
LaunchGoogleWeb : Success
---------------------------------------------------------------
---- Testing Inject Key Flow when Input Events are Disabled ----
Success: null
---------------------------------------------------------------
Request: {
"jsonrpc": "2.0",
"id": "5",
"method": "org.rdk.RDKWindowManager.ignoreKeyInputs",
"params": {"ignore": true} }
Expected: null
Result: null
testIgnoreKeyInputs_true : Success
---------------------------------------------------------------
---- Confirm on the WebKitBrowser application side that the physical key press [remote key press] is NOT accepted when IgnoreKey Inputs Disbled. ----
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 5
Success Test Count - 5
Failed Test Count - 0
---------------------------------------------------------------
-|23 | testIgnoreKeyInputsDisable |RDKWMJsonL3Test.sh testIgnoreKeyInputsDisable |Prerequisites:The RDK_WINDOW_MANAGER_ENABLE_KEY_IGNORE feature must be enabled (set to 1) for this function to execute.
1.create a display using the createDisplay API
2.Activate the WebKitBrowser plugin by invoking the Controller.1.activate
3.Load the Google homepage in the WebKitBrowser
4. Disable the ignoreKeyInputs feature by invoking the ignoreKeyInputs API with the enabled parameter set to false.
5.Verify that the response is null.
6.Attempt to press a key using the Remote Controller".
7.Confirm that the key injection is accepted on the application side when key inputs are ignored.| On Screen Display - Confirm that the key injection is accepted on the WebKitBrowser application side
From Logs: ignoreKeyInputs method request and response
\---------------------------------------------------------------
---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method": "org.rdk.RDKWindowManager.createDisplay", "params":{"displayParams":"{\"callsign\":\"googletestapp\", \"displayName\": \"wst-webkitbrowser\"}"}}
Expected: null
Result: null
CreateDisplayForGoogle : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.activate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserActivate : Success
---------------------------------------------------------------
Success: null
---------------------------------------------------------------
Request: {"jsonrpc":"2.0","id":"3","method":"WebKitBrowser.1.url","params":"http://www.google.com"}
Expected: null
Result: null
LaunchGoogleWeb : Success
---------------------------------------------------------------
---- Testing Inject Key Flow when Input Events are Disabled ----
Success: null
---------------------------------------------------------------
Request: {
"jsonrpc": "2.0",
"id": "5", "method": "org.rdk.RDKWindowManager.ignoreKeyInputs",
"params": {"ignore": false}
}
Expected: null
Result: null
testIgnoreKeyInputs_false : Success
---------------------------------------------------------------
---- Confirm on the WebKitBrowser application side that the physical key press [remote key press] is accepted when IgnoreKey Inputs Disbled. ----
Success: null
---------------------------------------------------------------
Request: {"jsonrpc": "2.0","id": 4,"method": "Controller.1.deactivate", "params": { "callsign": "WebKitBrowser"}}
Expected: null
Result: null
WebkitBrowserDeactivate : Success
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 5
Success Test Count - 5
Failed Test Count - 0
---------------------------------------------------------------
-|24 | testKeyRepeatConfigUnsupportedInput | RDKWMJsonL3Test.shtestKeyRepeatConfig_UnsupportedInput |
1. Attempt to configure keyRepeatConfig for an unsupported input type (e.g., "mouse") using the API.
2.Verify that the response contains an error with code: 1 and message: "ERROR_GENERAL".
3.Confirm that the key repeat configuration is not applied due to the missing parameter.|On screen display-NO
from Log confirm request and response of keyRepeatConfig
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "5", "method": "org.rdk.RDKWindowManager.keyRepeatConfig", "params": {"input": "mouse", "keyConfig": {"enabled": true, "initialDelay": 500, "repeatInterval": 100}}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testKeyRepeatConfig_UnsupportedInput : Success
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 1
Success Test Count - 1
Failed Test Count - 0
--------------------------------------------------------------- -|25 |testKeyRepeatConfigMissingEnabled| RDKWMJsonL3Test.sh testKeyRepeatConfig_MissingEnabled| 1.Invoke the keyRepeatConfig API for the "default" input, omitting the enabled parameter.
2.Verify that the response contains an error with code: 1 and message: "ERROR_GENERAL".
3.Confirm that the key repeat configuration is not applied due to the missing parameter.| On Screen Display - No
From Log Confirm request and response of keyRepeatConfig
---------------------------------------------------------------
Request: {"jsonrpc": "2.0", "id": "6", "method": "org.rdk.RDKWindowManager.keyRepeatConfig", "params": {"input": "default", "keyConfig": {"initialDelay": 500, "repeatInterval": 100}}}
Expected: "code":1,"message":"ERROR_GENERAL"
Result: "code":1,"message":"ERROR_GENERAL"
testKeyRepeatConfig_MissingEnabled : Success
---------------------------------------------------------------
---------------------------------------------------------------
Total Test Cases - 1
Success Test Count - 1
Failed Test Count - 0 -| 26 | testAll | RDKWMJsonL3Test.sh testAll | Run all the tests
Note:
1\. Do this After Fresh bootup,
2\. Stop the sky service using systemctl command

3\. Activate the RDKWindowManager Plugin using curl command

4\. Then run the testAll test command | On Screen Display - Come for testCreateDisplay1 and testCreateDisplay2
From Logs: createDisplay and getClients methods request and response

Same set of logs menitioned for each test will come, then final results will display
\---------------------------------------------------------------
Total Test Cases - 8
Success Test Count - 8
Failed Test Count - 0
\-------------------------------------------------------------- | | - - diff --git a/ResourceManager/CHANGELOG.md b/ResourceManager/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/ResourceManager/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/ResourceManager/CMakeLists.txt b/ResourceManager/CMakeLists.txt deleted file mode 100644 index 0358329..0000000 --- a/ResourceManager/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME ResourceManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_RESOURCE_MANAGER_AUTOSTART true CACHE STRING "Automatically start ResourceManager plugin") -set(PLUGIN_RESOURCE_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_RESOURCE_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start ResourceManager plugin") - -find_package(${NAMESPACE}Plugins REQUIRED) - -add_library(${MODULE_NAME} SHARED - ResourceManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers ) -set_source_files_properties(ResourceManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -set(RESOURCE_MANAGER_INCLUDES $ENV{RESOURCE_MANAGER_INCLUDES}) -separate_arguments(RESOURCE_MANAGER_INCLUDES) -include_directories(BEFORE ${RESOURCE_MANAGER_INCLUDES}) - -if (RDK_SERVICES_L1_TEST) - include_directories(${CMAKE_SOURCE_DIR}/Tests/L1Tests) - add_definitions(-DENABLE_L1TEST) -endif(RDK_SERVICES_L1_TEST) - -if (RDK_SERVICES_L1_TEST OR RDK_SERVICE_L2_TEST) - target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_RESOURCE_MANAGER_EXTRA_LIBRARIES}) -else() - target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins -lessosrmgr ${PLUGIN_RESOURCE_MANAGER_EXTRA_LIBRARIES}) -endif() - -if (RDK_SERVICE_L2_TEST) - target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) - target_compile_options(${MODULE_NAME} PRIVATE -Wno-error) - - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${MODULE_NAME} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) - add_definitions(-DENABLE_L1TEST) - add_definitions(-DENABLE_ERM) -endif (RDK_SERVICES_L2_TEST) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/ResourceManager/Module.cpp b/ResourceManager/Module.cpp deleted file mode 100644 index 334f35f..0000000 --- a/ResourceManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * * If not stated otherwise in this file or this component's LICENSE - * * file the following copyright and licenses apply: - * * - * * Copyright 2020 RDK Management - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * **/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/ResourceManager/Module.h b/ResourceManager/Module.h deleted file mode 100644 index 74326b5..0000000 --- a/ResourceManager/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * * If not stated otherwise in this file or this component's LICENSE - * * file the following copyright and licenses apply: - * * - * * Copyright 2020 RDK Management - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * **/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_ResourceManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/ResourceManager/README.md b/ResourceManager/README.md deleted file mode 100644 index 1ab3d7b..0000000 --- a/ResourceManager/README.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------ -# ResourceManager - -## Versions -`org.rdk.ResourceManager.1` - -## Methods: -``` -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.ResourceManager.setAVBlocked", "params": {"appid":"Netflix-0", "blocked":true}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.ResourceManager.getBlockedAVApplications"}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.ResourceManager.reserveTTSResource", "params": {"appid":"Netflix-0"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.ResourceManager.reserveTTSResourceForApps", "params": {"appids":["Netflix-0","com.bskyb.epgui"]}}' http://127.0.0.1:9998/jsonrpc -``` - -## Responses -``` -setAVBlocked: -{"jsonrpc":"2.0","id":3,"result":{"success":true}} -getBlockedAVApplications: -{"jsonrpc":"2.0","id":3,"result":{"clients":["Netflix-0],"success":true}} -reserveTTSResource: -{"jsonrpc":"2.0","id":3,"result":{"success":true}} -reserveTTSResourceForApps: -{"jsonrpc":"2.0","id":3,"result":{"success":true}} -``` - -## Events -``` -none -``` diff --git a/ResourceManager/ResourceManager.conf.in b/ResourceManager/ResourceManager.conf.in deleted file mode 100644 index 41be58f..0000000 --- a/ResourceManager/ResourceManager.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.ResourceManager" -autostart = "true" -startuporder = "@PLUGIN_RESOURCE_MANAGER_STARTUPORDER@" diff --git a/ResourceManager/ResourceManager.config b/ResourceManager/ResourceManager.config deleted file mode 100644 index 32e31eb..0000000 --- a/ResourceManager/ResourceManager.config +++ /dev/null @@ -1,7 +0,0 @@ -set (autostart true) -set (preconditions Platform) -set (callsign "org.rdk.ResourceManager") - -if(PLUGIN_RESOURCE_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_RESOURCE_MANAGER_STARTUPORDER}) -endif() diff --git a/ResourceManager/ResourceManager.cpp b/ResourceManager/ResourceManager.cpp deleted file mode 100644 index 62860ac..0000000 --- a/ResourceManager/ResourceManager.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/** - * * If not stated otherwise in this file or this component's LICENSE - * * file the following copyright and licenses apply: - * * - * * Copyright 2020 RDK Management - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * **/ - -#include "ResourceManager.h" -#include "UtilsgetRFCConfig.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 1 - -static std::string sThunderSecurityToken; -//methods -const string WPEFramework::Plugin::ResourceManager::RESOURCE_MANAGER_METHOD_SET_AV_BLOCKED = "setAVBlocked"; -const string WPEFramework::Plugin::ResourceManager::RESOURCE_MANAGER_METHOD_GET_BLOCKED_AV_APPLICATIONS = "getBlockedAVApplications"; -const string WPEFramework::Plugin::ResourceManager::RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE = "reserveTTSResource"; -const string WPEFramework::Plugin::ResourceManager::RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE_FOR_APPS = "reserveTTSResourceForApps"; - -namespace WPEFramework { - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin { - SERVICE_REGISTRATION(ResourceManager, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - ResourceManager* ResourceManager::_instance = nullptr; - ResourceManager::ResourceManager() - : PluginHost::JSONRPC() - { - Register(_T(RESOURCE_MANAGER_METHOD_SET_AV_BLOCKED), &ResourceManager::setAVBlockedWrapper, this); - Register(_T(RESOURCE_MANAGER_METHOD_GET_BLOCKED_AV_APPLICATIONS), &ResourceManager::getBlockedAVApplicationsWrapper, this); - Register(_T(RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE), &ResourceManager::reserveTTSResourceWrapper, this); - Register(_T(RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE_FOR_APPS), &ResourceManager::reserveTTSResourceWrapperForApps, this); - mEssRMgr = nullptr; - -#ifdef ENABLE_ERM - mEssRMgr = EssRMgrCreate(); - std::cout<<"EssRMgrCreate "<<((mEssRMgr != nullptr)?"succeeded":"failed")<QueryInterfaceByCallsign("SecurityAgent"); - if (security != nullptr) { - string payload = "http://localhost"; - string token; - if (security->CreateToken( - static_cast(payload.length()), - reinterpret_cast(payload.c_str()), - token) - == Core::ERROR_NONE) { - sThunderSecurityToken = token; - std::cout << "Resourcemanager got security token" << std::endl; - } else { - std::cout << "Resourcemanager failed to get security token" << std::endl; - } - security->Release(); - } else { - std::cout << "Resourcemanager : No security agent" << std::endl; - } - - - return (string()); - } - - void ResourceManager::Deinitialize(PluginHost::IShell * /* service */) - { - ResourceManager::_instance = nullptr; - } - - string ResourceManager::Information() const - { - return (string()); - } - - uint32_t ResourceManager::setAVBlockedWrapper(const JsonObject ¶meters, JsonObject &response) - { - LOGINFOMETHOD(); - - bool status = true; - if ((nullptr != mEssRMgr) && (false == mDisableBlacklist)) - { - if (parameters.HasLabel("appid") && parameters.HasLabel("blocked")) - { - std::string app = parameters["appid"].String(); - bool blockAV = parameters["blocked"].Boolean(); - std::cout<<"appid : "<< app << std::endl; - std::cout<<"blocked : "< apps; - status = getBlockedAVApplications(apps); - if (true == status) - { - std::string appCallSign; - for (std::vector::iterator appsItr = apps.begin(); appsItr != apps.end(); appsItr++) - { - appsList.Add(*appsItr); - // appCallSign = *appsItr; - // std::string::size_type pos = appCallSign.find(','); - // if (pos != std::string::npos) - // { - // appsList.Add(appCallSign.substr(0, pos)); - // } - } - } - } - else - { - response["message"] = "ERM not enabled"; - } - response["clients"]=appsList; - returnResponse(status); - } - - uint32_t ResourceManager::reserveTTSResourceWrapperForApps(const JsonObject ¶meters, JsonObject &response) - { - LOGINFOMETHOD(); - bool status = false; - - if ((parameters.HasLabel("appids")) && (false == mDisableReserveTTS)) - { - std::vector apps; - auto appArray = parameters["appids"].Array(); - for (uint32_t i = 0; i < appArray.Length(); ++i) { - apps.push_back(appArray[i].String()); - } - for (const auto& s : apps) { - std::cout << s << " "; - } - std::cout << std::endl; - - status = reserveTTSResourceForApps(apps); - } - else - { - if (mDisableReserveTTS) - { - status = true; - response["message"] = "ReserveTTS RFC is disabled"; - } - else - { - std::string jsonstr; - parameters.ToString(jsonstr); - std::cout<<"ERROR: appids are required in "<< jsonstr << std::endl; - } - } - - returnResponse(status); - } - - uint32_t ResourceManager::reserveTTSResourceWrapper(const JsonObject ¶meters, JsonObject &response) - { - LOGINFOMETHOD(); - bool status = false; - - if ((parameters.HasLabel("appid")) && (false == mDisableReserveTTS)) - { - std::string app = parameters["appid"].String(); - std::cout<<"appid : "<< app << std::endl; - - status = reserveTTSResource(app); - } - else - { - if (mDisableReserveTTS) - { - status = true; - response["message"] = "ReserveTTS RFC is disabled"; - } - else - { - std::string jsonstr; - parameters.ToString(jsonstr); - std::cout<<"ERROR: appid required in "<< jsonstr << std::endl; - } - } - - returnResponse(status); - } - - bool ResourceManager::setAVBlocked(const string& callsign, const bool blockAV) - { - bool status = true; -#ifdef ENABLE_ERM - status = blockAV?EssRMgrAddToBlackList(mEssRMgr, callsign.c_str()):EssRMgrRemoveFromBlackList(mEssRMgr, callsign.c_str()); - std::cout<<"setAVBlocked call returning "< &appsList) - { - bool status = false; -#ifdef ENABLE_ERM - std::cout<<"iterating mAppsAVBlacklistStatus ..." << std::endl; - std::map::iterator appsItr = mAppsAVBlacklistStatus.begin(); - for (;appsItr != mAppsAVBlacklistStatus.end(); appsItr++) - { - std::cout<<"app : " <first<< std::endl; - std::cout<<"blocked : "<second << std::endl; - if (true == appsItr->second) - { - appsList.push_back(appsItr->first); - } - } - status = true; -#endif - return status; - } - - struct JSONRPCDirectLink - { - private: - uint32_t mId { 0 }; - std::string mCallSign { }; -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - PluginHost::ILocalDispatcher * dispatcher_ {nullptr}; -#else - PluginHost::IDispatcher * dispatcher_ {nullptr}; -#endif - - Core::ProxyType Message() const - { - return (Core::ProxyType(PluginHost::IFactories::Instance().JSONRPC())); - } - - template - bool ToMessage(PARAMETERS& parameters, Core::ProxyType& message) const - { - return ToMessage((Core::JSON::IElement*)(¶meters), message); - } - bool ToMessage(Core::JSON::IElement* parameters, Core::ProxyType& message) const - { - if (!parameters->IsSet()) - return true; - string values; - if (!parameters->ToString(values)) - { - std::cout << "Failed to convert params to string\n"; - return false; - } - if (values.empty() != true) - { - message->Parameters = values; - } - return true; - } - template - bool FromMessage(RESPONSE& response, const Core::ProxyType& message, bool isResponseString=false) const - { - return FromMessage((Core::JSON::IElement*)(&response), message, isResponseString); - } - bool FromMessage(Core::JSON::IElement* response, const Core::ProxyType& message, bool isResponseString=false) const - { - Core::OptionalType error; - if ( !isResponseString && !response->FromString(message->Result.Value(), error) ) - { - std::cout << "Failed to parse response!!! Error: '" << error.Value().Message() << "'\n"; - return false; - } - return true; - } - - public: - JSONRPCDirectLink(PluginHost::IShell* service, std::string callsign) - : mCallSign(callsign) - { - if (service) -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - dispatcher_ = service->QueryInterfaceByCallsign(mCallSign); -#else - dispatcher_ = service->QueryInterfaceByCallsign(mCallSign); -#endif - } - - JSONRPCDirectLink(PluginHost::IShell* service) - : JSONRPCDirectLink(service, "Controller") - { - } - ~JSONRPCDirectLink() - { - if (dispatcher_) - dispatcher_->Release(); - } - - template - uint32_t Get(const uint32_t waitTime, const string& method, PARAMETERS& respObject) - { - JsonObject empty; - return Invoke(waitTime, method, empty, respObject); - } - - template - uint32_t Set(const uint32_t waitTime, const string& method, const PARAMETERS& sendObject) - { - JsonObject empty; - return Invoke(waitTime, method, sendObject, empty); - } - - template - uint32_t Invoke(const uint32_t waitTime, const string& method, const PARAMETERS& parameters, RESPONSE& response, bool isResponseString=false) - { - if (dispatcher_ == nullptr) { - std::cout << "No JSON RPC dispatcher for " << mCallSign << '\n'; - return Core::ERROR_GENERAL; - } - - auto message = Message(); - - message->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - message->Id = Core::JSON::DecUInt32(++mId); - message->Designator = Core::JSON::String(mCallSign + ".1." + method); - - ToMessage(parameters, message); - - const uint32_t channelId = ~0; -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - string output = ""; - uint32_t result = Core::ERROR_BAD_REQUEST; - - if (dispatcher_ != nullptr) { - PluginHost::ILocalDispatcher* localDispatcher = dispatcher_->Local(); - - ASSERT(localDispatcher != nullptr); - - if (localDispatcher != nullptr) - result = dispatcher_->Invoke(channelId, message->Id.Value(), sThunderSecurityToken, message->Designator.Value(), message->Parameters.Value(),output); - } - - if (message.IsValid() == true) { - if (result == static_cast(~0)) { - message.Release(); - } - else if (result == Core::ERROR_NONE) - { - if (output.empty() == true) - message->Result.Null(true); - else - message->Result = output; - } - else - { - message->Error.SetError(result); - if (output.empty() == false) { - message->Error.Text = output; - } - } - } - - if (!FromMessage(response, message, isResponseString)) - { - return Core::ERROR_GENERAL; - } -#elif (THUNDER_VERSION == 2) - auto resp = dispatcher_->Invoke(sThunderSecurityToken, channelId, *message); -#else - Core::JSONRPC::Context context(channelId, message->Id.Value(), sThunderSecurityToken) ; - auto resp = dispatcher_->Invoke(context, *message); -#endif - -#if ((THUNDER_VERSION == 2) || (THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 2)) - - if (resp->Error.IsSet()) { - std::cout << "Call failed: " << message->Designator.Value() << " error: " << resp->Error.Text.Value() << "\n"; - return resp->Error.Code; - } - - if (!FromMessage(response, resp, isResponseString)) - return Core::ERROR_GENERAL; -#endif - return Core::ERROR_NONE; - } - }; - - bool ResourceManager::reserveTTSResource(const string& client) - { - uint32_t ret = Core::ERROR_NONE; - bool status = false; - - JsonObject params; - JsonObject result; - JsonObject clientParam; - JsonArray clientList = JsonArray(); - JsonArray accessList = JsonArray(); - - clientList.Add(client); - clientParam.Set("method", "speak"); - clientParam["apps"] = clientList; - accessList.Add(clientParam); - params["accesslist"] = accessList; - - std::string jsonstr; - params.ToString(jsonstr); - std::cout<<"Resourcemanager : about to call setACL : "<< jsonstr << std::endl; - - ret = JSONRPCDirectLink(mCurrentService, "org.rdk.TextToSpeech").Invoke(20000, "setACL", params, result); - - status = ((Core::ERROR_NONE == ret) && (result.HasLabel("success")) && (result["success"].Boolean())); - - result.ToString(jsonstr); - std::cout<<"setACL response : "<< jsonstr << std::endl; - std::cout<<"setACL status : "<& clients) - { - uint32_t ret = Core::ERROR_NONE; - bool status = false; - - JsonObject params; - JsonObject result; - JsonArray accessList; - JsonObject clientParam; - JsonArray clientList; - for (const auto& client : clients) { - clientList.Add(client); - } - clientParam.Set("method", "speak"); - clientParam["apps"] = clientList; - accessList.Add(clientParam); - params["accesslist"] = accessList; - - std::string jsonstr; - params.ToString(jsonstr); - std::cout<<"Resourcemanager : about to call setACL : "<< jsonstr << std::endl; - - ret = JSONRPCDirectLink(mCurrentService, "org.rdk.TextToSpeech").Invoke(20000, "setACL", params, result); - - status = ((Core::ERROR_NONE == ret) && (result.HasLabel("success")) && (result["success"].Boolean())); - - result.ToString(jsonstr); - std::cout<<"setACL response : "<< jsonstr << std::endl; - std::cout<<"setACL status : "< -#include "essos-resmgr.h" -#endif -#include -#include - -#include "UtilsJsonRpc.h" - -namespace WPEFramework { - - namespace Plugin { - - class ResourceManager : public PluginHost::IPlugin, public PluginHost::JSONRPC { - public: - ResourceManager(); - virtual ~ResourceManager(); - - BEGIN_INTERFACE_MAP(ResourceManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - // IPlugin methods - virtual const string Initialize(PluginHost::IShell* service) override; - virtual void Deinitialize(PluginHost::IShell* service) override; - virtual string Information() const override; - - public/*members*/: - static ResourceManager* _instance; - - public /*constants*/: - static const string SERVICE_NAME; - //methods - static const string RESOURCE_MANAGER_METHOD_SET_AV_BLOCKED; - static const string RESOURCE_MANAGER_METHOD_GET_BLOCKED_AV_APPLICATIONS; - static const string RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE; - static const string RESOURCE_MANAGER_METHOD_RESERVE_TTS_RESOURCE_FOR_APPS; - - private/*registered methods (wrappers)*/: - //methods ("parameters" here is "params" from the curl request) - uint32_t setAVBlockedWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t getBlockedAVApplicationsWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t reserveTTSResourceWrapper(const JsonObject& parameters, JsonObject& response); - uint32_t reserveTTSResourceWrapperForApps(const JsonObject& parameters, JsonObject& response); - - // private/*internal methods*/: changing private to protected for testing purpose - protected: - ResourceManager(const ResourceManager&) = delete; - ResourceManager& operator=(const ResourceManager&) = delete; - - bool setAVBlocked(const string& client, const bool blocked); - bool getBlockedAVApplications(std::vector &appsList); - bool reserveTTSResource(const string& client); - bool reserveTTSResourceForApps(const std::vector& clients); - - #if defined(ENABLE_ERM) || defined(ENABLE_L1TEST) - EssRMgr* mEssRMgr; - #endif - - bool mDisableBlacklist; - bool mDisableReserveTTS; - PluginHost::IShell* mCurrentService; - std::map mAppsAVBlacklistStatus; - - }; - - } // namespace Plugin -} // namespace WPEFramework diff --git a/RuntimeManager/AIConfiguration.cpp b/RuntimeManager/AIConfiguration.cpp deleted file mode 100755 index e2191c6..0000000 --- a/RuntimeManager/AIConfiguration.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "AIConfiguration.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include -#include -#include - -#define AICONFIGURATION_INI_PATH "/opt/demo/config.ini" - -extern char **environ; - -namespace WPEFramework -{ -namespace Plugin -{ - AIConfiguration::AIConfiguration() - { - } - - AIConfiguration::~AIConfiguration() - { - } - - void AIConfiguration::initialize() - { - readFromConfigFile(); - } - - size_t AIConfiguration::getContainerConsoleLogCap() - { - return mConsoleLogCap; - } - - std::bitset<32> AIConfiguration::getAppsCpuSet() const - { - return mAppsCpuSet; - } - - ssize_t AIConfiguration::getNonHomeAppMemoryLimit() - { - return mNonHomeAppMemoryLimit; - } - - ssize_t AIConfiguration::getNonHomeAppGpuLimit() - { - return mNonHomeAppGpuLimit; - } - - std::list AIConfiguration::getVpuAccessBlacklist() const - { - return mVpuAccessBlacklist; - } - - std::list AIConfiguration::getAppsRequiringDBus() const - { - return mAppsRequiringDBus; - } - - std::list AIConfiguration::getMapiPorts() const - { - return mMapiPorts; - } - - bool AIConfiguration::getResourceManagerClientEnabled() const - { - return mResourceManagerClientEnabled; - } - - bool AIConfiguration::getGstreamerRegistryEnabled() - { - return mGstreamerRegistryEnabled; - } - - bool AIConfiguration::getSvpEnabled() - { - return mSvpEnabled; - } - - bool AIConfiguration::getEnableUsbMassStorage() - { - return mEnableUsbMassStorage; - } - - bool AIConfiguration::getIPv6Enabled() - { - return mIPv6Enabled; - } - - size_t AIConfiguration::getIonHeapDefaultQuota() const - { - return mIonHeapDefaultQuota; - } - - in_port_t AIConfiguration::getDialServerPort() const - { - return mDialServerPort; - } - - std::string AIConfiguration::getDialServerPathPrefix() const - { - return mDialServerPathPrefix; - } - - std::string AIConfiguration::getDialUsn() const - { - return mDialUsn; - } - - std::list AIConfiguration::getPreloads() const - { - return mPreloads; - } - std::list AIConfiguration::readGlobalEnv() const - { - std::list environmentVariables; - char **envList = environ; - - for (;*envList;envList++) - { - environmentVariables.emplace_back(*envList); - } - return environmentVariables; - } - - std::list AIConfiguration::getEnvs() const - { - return mEnvVariables; - } - - std::map AIConfiguration::getIonHeapQuotas() const - { - return mIonHeapQuotas; - } - - void AIConfiguration::readFromCustomData() - { - mConsoleLogCap = 1 * 1024 * 1024; //.apps.limits.consoleLogBytes - mAppsCpuSet = 0xff; //.apps.limits.cpuset - mNonHomeAppMemoryLimit = 200 * 1024 * 1024; //.apps.limits.memory.defaultLimitBytes - mNonHomeAppGpuLimit = 64 * 1024 * 1024; //.apps.limits.memory.defaultLimitBytes - /* mVpuAccessBlacklist - apps.vpuAccessBlacklist */ - /* mAppsRequiringDBusList - apps.requireDBus */ - /* mMapiPorts = apps.mapi.ports */ - mResourceManagerClientEnabled = false; // .apps.essosResourceManager.enableClient - mGstreamerRegistryEnabled = false; // apps.gstreamer.mapCachedRegistry - mSvpEnabled = false; // apps.svp.enable - mEnableUsbMassStorage = false; // apps.usbMassStorage.enable - mIPv6Enabled = false; // apps.enableIPv6 - mIonHeapDefaultQuota = 256 * 1024 * 1024; // apps.limits.ion.defaultLimitBytes - mDialServerPort = 8009; //.dial.server.port; - mDialServerPathPrefix = ""; // dial.server.prefix - mDialUsn = ""; //.dial.usn - //mPreloads - - //TODO: SUPPORT Dial - /* - if (mDialServerPathPrefix.empty()) - { - auto dialUuid = AICommon::Uuid::createUuid(); - mDialServerPathPrefix = dialUuid.toString(); - } - if (mDialUsn.empty()) - { - AICommon::DthMacAddressProvider macAddressProvider; - mDialUsn = AICommon::getDeviceDialUsn(macAddressProvider.getMac()); - } - */ - mEnvVariables.push_back("WESTEROS_SINK_AMLOGIC_USE_DMABUF=1"); - mEnvVariables.push_back("WESTEROS_GL_USE_AMLOGIC_AVSYNC=1"); - mEnvVariables.push_back("WESTEROS_SINK_USE_FREERUN=1"); - mEnvVariables.push_back("WESTEROS_GL_MODE=3840x2160x60"); - mEnvVariables.push_back("WESTEROS_GL_GRAPHICS_MAX_SIZE=1920x1080"); - mEnvVariables.push_back("WESTEROS_GL_USE_REFRESH_LOCK=1"); - } - - // helper functions for json parsing - std::list parseStringArray(std::string key, std::string value) - { - std::list result; - - Json::Value root; - Json::Reader reader; - - if (!reader.parse(value, root)) - { - LOGERR("Failed to parse JSON for - %s", key.c_str()); - return {}; - } - - for (const auto &val : root) - { - result.push_back(val.asString()); - } - - return result; - } - - std::list parseIntArray(std::string value) - { - std::list result; - - Json::Value root; - Json::Reader reader; - - if (!reader.parse(value, root)) - { - LOGERR("Failed to parse JSON for int array"); - return {}; - } - - for (const auto &val : root) - { - result.push_back(val.asInt()); - } - - return result; - } - - std::map parseIonLimits(std::string value) - { - std::map result; - - Json::Value root; - Json::Reader reader; - - if (!reader.parse(value, root)) - { - LOGERR("Failed to parse JSON for ionLimits"); - return {}; - } - - for (const auto &key : root.getMemberNames()) - { - result[key] = root[key].asUInt(); - } - - return result; - } - - void AIConfiguration::printAIConfiguration() - { - // Output parsed values for verification using member variables - - std::string vpuBlacklistStr = ""; - for (const auto &item : mVpuAccessBlacklist) - { - vpuBlacklistStr += item + " "; - } - - std::string dbusAppsStr = ""; - for (const auto &item : mAppsRequiringDBus) - { - dbusAppsStr += item + " "; - } - - std::string mapiPortsStr = ""; - for (const auto &port : mMapiPorts) - { - mapiPortsStr += std::to_string(port) + " "; - } - - std::string preloadsStr = ""; - for (const auto &lib : mPreloads) - { - preloadsStr += lib + " "; - } - - std::string envsStr = ""; - for (const auto &env : mEnvVariables) - { - envsStr += env + " "; - } - - LOGINFO("consoleLogCap: %zu", mConsoleLogCap); - LOGINFO("appsCpuSet: 0x%08lx", mAppsCpuSet.to_ulong()); - LOGINFO("nonHomeAppMemoryLimit: %zd", mNonHomeAppMemoryLimit); - LOGINFO("nonHomeAppGpuLimit: %zd", mNonHomeAppGpuLimit); - LOGINFO("vpuAccessBlacklist: %s", vpuBlacklistStr.c_str()); - LOGINFO("appsRequiringDBus: %s", dbusAppsStr.c_str()); - LOGINFO("mapiPorts: %s", mapiPortsStr.c_str()); - LOGINFO("resourceManagerClientEnabled: %s", mResourceManagerClientEnabled ? "true" : "false"); - LOGINFO("gstreamerRegistryEnabled: %s", mGstreamerRegistryEnabled ? "true" : "false"); - LOGINFO("svpEnabled: %s", mSvpEnabled ? "true" : "false"); - LOGINFO("enableUsbMassStorage: %s", mEnableUsbMassStorage ? "true" : "false"); - LOGINFO("ipv6Enabled: %s", mIPv6Enabled ? "true" : "false"); - LOGINFO("ionHeapDefaultQuota: %zu", mIonHeapDefaultQuota); - LOGINFO("dialServerPort: %u", static_cast(mDialServerPort)); - LOGINFO("dialServerPathPrefix: %s", mDialServerPathPrefix.c_str()); - LOGINFO("dialUsn: %s", mDialUsn.c_str()); - LOGINFO("ionHeapQuotas:"); - for (const auto &pair : mIonHeapQuotas) - { - LOGINFO(" Name: %s, Limit: %zu", pair.first.c_str(), pair.second); - } - LOGINFO("preloads: %s", preloadsStr.c_str()); - LOGINFO("envVariables: %s", envsStr.c_str()); - } - - void AIConfiguration::readFromConfigFile() - { - //TODO SUPPORT DEVICE_FRIENDLYNAME - //TODO SUPPORT DEVICE_MODEL_NUM - //TODO SUPPORT PARTNER_ID - //TODO SUPPORT REGION=USA, - //TODO SUPPORT LANG=en_US - //TODO SUPPORT STB_ENTITLEMENTS - - std::list gEnv = readGlobalEnv(); - mEnvVariables.insert(mEnvVariables.end(),gEnv.begin(),gEnv.end()); - LOGINFO("AIConfiguration reading from config file at %s", AICONFIGURATION_INI_PATH); - std::ifstream iniFile(AICONFIGURATION_INI_PATH); - if (!iniFile.is_open()) - { - LOGERR("Failed to open the ini file at %s", AICONFIGURATION_INI_PATH); - LOGINFO("Populating custom values for AIConfiguration from readFromCustomData()"); - readFromCustomData(); - return; - } - - std::string line; - while (std::getline(iniFile, line)) - { - // Skip empty lines - if (line.empty()) - continue; - - // Remove leading and trailing whitespace - line.erase(0, line.find_first_not_of(" \t")); - line.erase(line.find_last_not_of(" \t") + 1); - - // Skip comments - if (line[0] == '#') - continue; - - std::istringstream iss(line); - std::string key, value; - if (std::getline(iss, key, '=') && std::getline(iss, value)) - { - key.erase(key.find_last_not_of(" \t") + 1); // Trim trailing spaces - value.erase(0, value.find_first_not_of(" \t")); // Trim leading spaces - - if (key == "consoleLogCap") - { - mConsoleLogCap = static_cast(std::stoull(value)); - } - else if (key == "cores") - { - mAppsCpuSet = std::bitset<32>(std::stoul(value)); - } - else if (key == "ramLimit") - { - mNonHomeAppMemoryLimit = static_cast(std::stoll(value)); - } - else if (key == "gpuMemoryLimit") - { - mNonHomeAppGpuLimit = static_cast(std::stoll(value)); - } - else if (key == "vpuAccessBlacklist") - { - mVpuAccessBlacklist = parseStringArray(key, value); - } - else if (key == "appsRequiringDBus") - { - mAppsRequiringDBus = parseStringArray(key, value); - } - else if (key == "mapiPorts") - { - mMapiPorts = parseIntArray(value); - } - else if (key == "resourceManagerClientEnabled") - { - mResourceManagerClientEnabled = (value == "1" || value == "true"); - } - else if (key == "gstreamerRegistryEnabled") - { - mGstreamerRegistryEnabled = (value == "1" || value == "true"); - } - else if (key == "svpEnabled") - { - mSvpEnabled = (value == "1" || value == "true"); - } - else if (key == "enableUsbMassStorage") - { - mEnableUsbMassStorage = (value == "1" || value == "true"); - } - else if (key == "ipv6Enabled") - { - mIPv6Enabled = (value == "1" || value == "true"); - } - else if (key == "ionDefaultLimit") - { - mIonHeapDefaultQuota = static_cast(std::stoull(value)); - } - else if (key == "dialServerPort") - { - mDialServerPort = static_cast(std::stoul(value)); - } - else if (key == "dialServerPathPrefix") - { - // Remove surrounding quotes if present - if (!value.empty() && value.front() == '"' && value.back() == '"') - { - value = value.substr(1, value.size() - 2); - } - mDialServerPathPrefix = value; - } - else if (key == "dialUsn") - { - // Remove surrounding quotes if present - if (!value.empty() && value.front() == '"' && value.back() == '"') - { - value = value.substr(1, value.size() - 2); - } - mDialUsn = value; - } - else if (key == "ionLimits") - { - mIonHeapQuotas = parseIonLimits(value); - } - else if (key == "preloads") - { - mPreloads = parseStringArray(key, value); - } - else if (key == "envVariables") - { - mEnvVariables = parseStringArray(key, value); - } - } - } - - iniFile.close(); - - printAIConfiguration(); - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/AIConfiguration.h b/RuntimeManager/AIConfiguration.h deleted file mode 100755 index a303a6f..0000000 --- a/RuntimeManager/AIConfiguration.h +++ /dev/null @@ -1,90 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace WPEFramework -{ -namespace Plugin -{ - class AIConfiguration - { - public: - AIConfiguration(); - virtual ~AIConfiguration(); - void initialize(); - size_t getContainerConsoleLogCap(); - std::bitset<32> getAppsCpuSet() const; - ssize_t getNonHomeAppMemoryLimit(); - ssize_t getNonHomeAppGpuLimit(); - std::list getVpuAccessBlacklist() const; - std::list getAppsRequiringDBus() const; - std::list getMapiPorts() const; - bool getResourceManagerClientEnabled() const; - bool getGstreamerRegistryEnabled(); - bool getSvpEnabled(); - bool getEnableUsbMassStorage(); - bool getIPv6Enabled(); - size_t getIonHeapDefaultQuota() const; - in_port_t getDialServerPort() const; - std::string getDialServerPathPrefix() const; - std::string getDialUsn() const; - std::map getIonHeapQuotas() const; - void printAIConfiguration(); - - // system configuration - std::list getPreloads() const; - std::list getEnvs() const; - - private: - void readFromCustomData(); - void readFromConfigFile(); - std::listreadGlobalEnv() const; - - size_t mConsoleLogCap; - std::bitset<32> mAppsCpuSet; // cores - ssize_t mNonHomeAppMemoryLimit; // ramLimit - ssize_t mNonHomeAppGpuLimit; // gpuMemoryLimit - std::list mVpuAccessBlacklist; - std::list mAppsRequiringDBus; - std::list mMapiPorts; - bool mResourceManagerClientEnabled; - bool mGstreamerRegistryEnabled; - bool mSvpEnabled; - bool mEnableUsbMassStorage; - bool mIPv6Enabled; - size_t mIonHeapDefaultQuota; // ionDefaultLimit - in_port_t mDialServerPort; - std::string mDialServerPathPrefix; - std::string mDialUsn; - std::map mIonHeapQuotas; // ionLimits - - // system configuration - std::list mPreloads; - std::list mEnvVariables; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/ApplicationConfiguration.h b/RuntimeManager/ApplicationConfiguration.h deleted file mode 100755 index eb521cd..0000000 --- a/RuntimeManager/ApplicationConfiguration.h +++ /dev/null @@ -1,65 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -namespace WPEFramework -{ -namespace Plugin -{ - - typedef struct _AppStorageInfo - { - std::string path; - int32_t userId; - int32_t groupId; - uint32_t size; - uint32_t used; - } AppStorageInfo; - - struct ApplicationConfiguration - { - std::string mAppId; - - std::string mAppInstanceId; - - std::vector mArgs; - - // userId used by the container - uint32_t mUserId; - - // groupId used by the container - uint32_t mGroupId; - - std::vector mPorts; - - // westeros socket path that the containerized app should use to communicate with compositor - std::string mWesterosSocketPath; - - // TODO what to do with it? - std::vector mDebugSettings; - - // application storage info - storage path, uid, gid - AppStorageInfo mAppStorageInfo; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/CHANGELOG.md b/RuntimeManager/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/RuntimeManager/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/RuntimeManager/CMakeLists.txt b/RuntimeManager/CMakeLists.txt deleted file mode 100755 index 0eaaa26..0000000 --- a/RuntimeManager/CMakeLists.txt +++ /dev/null @@ -1,127 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME RuntimeManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_RUNTIME_MANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_RUNTIME_MANAGER_AUTOSTART false CACHE STRING "Automatically start RuntimeManager plugin") -set(PLUGIN_RUNTIME_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_RUNTIME_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start RuntimeManager plugin") -set(PLUGIN_RUNTIME_APP_PORTAL "" CACHE STRING "Runtime application portal identifier") - -option(AIMANAGERS_TELEMETRY_METRICS_SUPPORT "AIMANAGERS_TELEMETRY_METRICS_SUPPORT" OFF) - -add_definitions(-DRUNTIME_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DRUNTIME_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DRUNTIME_MANAGER_API_VERSION_NUMBER_PATCH=0) - -set(RUNTIME_MANAGER_IMPLEMENTATION ${PLUGIN_NAME}Implementation) -add_definitions(-DPLUGIN_RUNTIME_MANAGER_IMPLEMENTATION_NAME="${RUNTIME_MANAGER_IMPLEMENTATION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - RuntimeManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(RuntimeManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -set (RUNTIMEMANAGER_SOURCES) -list(APPEND RUNTIMEMANAGER_SOURCES RuntimeManagerImplementation.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES DobbySpecGenerator.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES WindowManagerConnector.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES DobbyEventListener.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES UserIdManager.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES AIConfiguration.cpp) -list(APPEND RUNTIMEMANAGER_SOURCES Module.cpp) - -if (RIALTO_IN_DAC_FEATURE) - add_definitions("-DRIALTO_IN_DAC_FEATURE_ENABLED") - list(APPEND RUNTIMEMANAGER_SOURCES RialtoConnector.cpp) -endif(RIALTO_IN_DAC_FEATURE) - - -add_library(${PLUGIN_IMPLEMENTATION} SHARED ${RUNTIMEMANAGER_SOURCES}) - -if (RIALTO_IN_DAC_FEATURE) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins RialtoServerManager) -endif(RIALTO_IN_DAC_FEATURE) - -if(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - message(STATUS "AIMANAGERS_TELEMETRY_METRICS_SUPPORT is enabled") - add_definitions(-DENABLE_AIMANAGERS_TELEMETRY_METRICS) -endif(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - -if(RDK_APPMANAGERS_DEBUG) - message(STATUS "Enable APP Manager debug support") - add_definitions("-DRDK_APPMANAGERS_DEBUG") -endif() - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set( AI_BUILD_TYPE "DEBUG" ) -add_definitions( -DAI_DEBUG=1 -DAI_RELEASE=2 ) -if( AI_BUILD_TYPE STREQUAL "RELEASE" ) - add_definitions( -DAI_BUILD_TYPE=AI_RELEASE ) -elseif( AI_BUILD_TYPE STREQUAL "DEBUG" ) - add_definitions( -DAI_BUILD_TYPE=AI_DEBUG ) -else() - message( FATAL_ERROR "AI_BUILD_TYPE '${AI_BUILD_TYPE}' not supported" ) -endif() - -set(RUNTIME_MANAGER_INCLUDES $ENV{RUNTIME_MANAGER_INCLUDES}) -separate_arguments(RUNTIME_MANAGER_INCLUDES) -include_directories(BEFORE ${RUNTIME_MANAGER_INCLUDES}) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${PLUGIN_RUNTIME_MANAGER_EXTRA_LIBRARIES}) - -if(RDK_SERVICES_L1_TEST) - set(JSONCPP_INCLUDE_PATH "/usr/include/jsoncpp" CACHE PATH "Path to jsoncpp includes") - include_directories(BEFORE ${JSONCPP_INCLUDE_PATH}) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE jsoncpp curl) -endif() - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/RuntimeManager/DobbyEventListener.cpp b/RuntimeManager/DobbyEventListener.cpp deleted file mode 100644 index 266189e..0000000 --- a/RuntimeManager/DobbyEventListener.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "DobbyEventListener.h" -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include - -#define SEND_EVENT_TO_RUNTIME_MANAGER(eventMethod, name, data) \ - if ((_parent.mEventHandler) != nullptr) \ - { \ - (_parent.mEventHandler)->eventMethod(name, data); \ - } \ - else \ - { \ - LOGERR("Event handler is null"); \ - } - -namespace WPEFramework { - namespace Plugin { - - DobbyEventListener::DobbyEventListener() - : mOCIContainerNotification(this),mEventHandler(nullptr) - { - LOGINFO("Creating DobbyEventListener instance"); - } - - DobbyEventListener::~DobbyEventListener() - { - LOGINFO("Delete DobbyEventListener instance"); - } - - bool DobbyEventListener::initialize(PluginHost::IShell* service, IEventHandler* eventHandler, Exchange::IOCIContainer* ociContainerObject) - { - bool ret = false; - mEventHandler = eventHandler; - mOCIContainerObject = ociContainerObject; - if (nullptr == mOCIContainerObject) - { - LOGERR("Failed to get OCIContainer object"); - } - else - { - Core::hresult registerResult = mOCIContainerObject->Register(&mOCIContainerNotification); - if(Core::ERROR_NONE != registerResult) - { - LOGERR("Failed to register OCIContainerNotification"); - return false; - } - else - { - LOGINFO("OCIContainerNotification registered successfully"); - } - ret = true; - } - return ret; - } - - bool DobbyEventListener::deinitialize() - { - if (nullptr != mOCIContainerObject) - { - Core::hresult unregisterResult = mOCIContainerObject->Unregister(&mOCIContainerNotification); - if(Core::ERROR_NONE != unregisterResult) - { - LOGERR("Failed to unregister OCIContainerNotification"); - } - mOCIContainerObject = nullptr; - } - return true; - } - - void DobbyEventListener::OCIContainerNotification::OnContainerStarted(const string& containerId, const string& name) - { - // LOGINFO("OnContainer started: %s", name.c_str()); - JsonObject data; - data["containerId"] = containerId; - data["name"] = name; - data["eventName"] = "onContainerStarted"; - SEND_EVENT_TO_RUNTIME_MANAGER(onOCIContainerStartedEvent, name, data); - } - - void DobbyEventListener::OCIContainerNotification::OnContainerStopped(const string& containerId, const string& name) - { - // LOGINFO("Container stopped: %s", name.c_str()); - JsonObject data; - data["containerId"] = containerId; - data["name"] = name; - data["eventName"] = "onContainerStopped"; - SEND_EVENT_TO_RUNTIME_MANAGER(onOCIContainerStoppedEvent, name, data); - } - - void DobbyEventListener::OCIContainerNotification::OnContainerFailed(const string& containerId, const string& name, uint32_t error) - { - // LOGINFO("Container failed: %s", name.c_str()); - JsonObject data; - data["containerId"] = containerId; - data["name"] = name; - data["errorCode"] = error; - data["eventName"] = "onContainerFailed"; - SEND_EVENT_TO_RUNTIME_MANAGER(onOCIContainerFailureEvent, name, data); - } - - void DobbyEventListener::OCIContainerNotification::OnContainerStateChanged(const string& containerId, Exchange::IOCIContainer::ContainerState state) - { - Exchange::IRuntimeManager::RuntimeState runtimeState; - switch(state) - { - case Exchange::IOCIContainer::ContainerState::STARTING: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_STARTING; - break; - case Exchange::IOCIContainer::ContainerState::RUNNING: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING; - break; - case Exchange::IOCIContainer::ContainerState::STOPPING: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_TERMINATING; - break; - case Exchange::IOCIContainer::ContainerState::PAUSED: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_SUSPENDED; - break; - case Exchange::IOCIContainer::ContainerState::STOPPED: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_TERMINATED; - break; - case Exchange::IOCIContainer::ContainerState::HIBERNATING: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_HIBERNATING; - break; - case Exchange::IOCIContainer::ContainerState::HIBERNATED: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_HIBERNATED; - break; - case Exchange::IOCIContainer::ContainerState::AWAKENING: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_WAKING; - break; - default: - runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_UNKNOWN; - break; - } - JsonObject data; - data["containerId"] = containerId; - data["state"] = static_cast(runtimeState); - data["eventName"] = "onContainerStateChanged"; - LOGINFO("Container state changed: %s state: %d runtimeState: %d", containerId.c_str(), static_cast(state), static_cast(runtimeState)); - SEND_EVENT_TO_RUNTIME_MANAGER(onOCIContainerStateChangedEvent, containerId, data); - } - - - - - - }// Namespace Plugin -}// Namespace WPEFramework \ No newline at end of file diff --git a/RuntimeManager/DobbyEventListener.h b/RuntimeManager/DobbyEventListener.h deleted file mode 100644 index 025eac3..0000000 --- a/RuntimeManager/DobbyEventListener.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include -#include -#include "IEventHandler.h" - -namespace WPEFramework { - namespace Plugin { - class DobbyEventListener - { - class OCIContainerNotification : public Exchange::IOCIContainer::INotification - { - private: - OCIContainerNotification(const OCIContainerNotification&) = delete; - OCIContainerNotification& operator=(const OCIContainerNotification&) = delete; - - public: - explicit OCIContainerNotification(DobbyEventListener* parent) - : _parent(*parent) - { - } - - virtual void OnContainerStarted(const string& containerId, const string& name) override; - virtual void OnContainerStopped(const string& containerId, const string& name) override; - virtual void OnContainerFailed(const string& containerId, const string& name, uint32_t error) override; - virtual void OnContainerStateChanged(const string& containerId, Exchange::IOCIContainer::ContainerState state) override; - - ~OCIContainerNotification() override = default; - BEGIN_INTERFACE_MAP(OCIContainerNotification) - INTERFACE_ENTRY(Exchange::IOCIContainer::INotification) - END_INTERFACE_MAP - - - private: - DobbyEventListener& _parent; - }; - - public: - DobbyEventListener(); - ~DobbyEventListener(); - - public: - bool initialize(PluginHost::IShell* service, IEventHandler* eventHandler, Exchange::IOCIContainer* ociContainerObject); - bool deinitialize(); - - private: - Exchange::IOCIContainer* mOCIContainerObject; - Core::Sink mOCIContainerNotification; - IEventHandler* mEventHandler; - - }; -} // namespace Plugin -} // namespace WPEFramework \ No newline at end of file diff --git a/RuntimeManager/DobbySpecGenerator.cpp b/RuntimeManager/DobbySpecGenerator.cpp deleted file mode 100755 index b872b3f..0000000 --- a/RuntimeManager/DobbySpecGenerator.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "DobbySpecGenerator.h" -#include "ApplicationConfiguration.h" -#include "UtilsLogging.h" -#include -#include -#include -#include -#include -#include -#include -//TODO SUPPORT THIS -//#include -#include - -namespace WPEFramework -{ -namespace Plugin -{ - -namespace -{ - #define XDG_RUNTIME_DIR "/tmp" -} - -DobbySpecGenerator::DobbySpecGenerator(): mIonMemoryPluginData(Json::objectValue), mPackageMountPoint("/package"), mRuntimeMountPoint("/runtime"), mGstRegistrySourcePath(""), mGstRegistryDestinationPath("/tmp/gstreamer-cached-registry.bin") -{ - LOGINFO("DobbySpecGenerator()"); - mAIConfiguration = new AIConfiguration(); - mAIConfiguration->initialize(); - initialiseIonHeapsJson(); -//TODO SUPPORT THIS -/* - if (mAIConfiguration->getGstreamerRegistryEnabled()) - { - GStreamerRegistry gstRegistry; - if (gstRegistry.generate()) - { - mGstRegistrySourcePath = gstRegistry.path(); - } - } -*/ -} - -DobbySpecGenerator::~DobbySpecGenerator() -{ - LOGINFO("~DobbySpecGenerator()"); - if (nullptr != mAIConfiguration) - { - delete mAIConfiguration; - } -} - -Json::Value DobbySpecGenerator::getWorkingDir(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - // default to the package directory - std::string workingDir(mPackageMountPoint); - - // TODO SUPPORT execFilePath in runtime config - appPath - /* - char *execFilePathCopy = strdup(appPackage->execFilePath().c_str()); //Get it from metadata path - const char* execFileDir = dirname(execFilePathCopy); - if (execFileDir && (strcmp(execFileDir, ".") != 0)) - workingDir += execFileDir; - - free(execFilePathCopy); - */ - return Json::Value(workingDir); -} - -bool DobbySpecGenerator::generate(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, string& resultSpec) -{ - LOGINFO("DobbySpecGenerator::generate()"); - resultSpec = ""; - - std::ifstream inFile("/tmp/specchange"); - if (inFile.good()) - { - inFile.open("/tmp/specchange"); //open the input file - std::stringstream strStream; - strStream << inFile.rdbuf(); //read the file - resultSpec = strStream.str(); //str holds the content of the file - std::cout << resultSpec << "\n"; //you can do anything with the string!!! - inFile.close(); - JsonObject parameters; - parameters.FromString(resultSpec.c_str()); - return true; - } - - ssize_t memLimit = getSysMemoryLimit(config, runtimeConfig); - /*mandatory parameter check*/ - if((memLimit <= 0) || runtimeConfig.command.empty() || (config.mUserId ==0)) - { - LOGERR("Invalid mandatory parameter: Mem Limit=%d, Command=%s UserId %d", memLimit, runtimeConfig.command.c_str(), config.mUserId); - return false; - } - - Json::Value spec; - spec["version"] = "1.1"; - spec["memLimit"] = std::move(memLimit); - - Json::Value args(Json::arrayValue); - std::string command =""; - if(!runtimeConfig.runtimePath.empty()) - { - command = "/runtime/"; - } - else - { - command = "/package/"; - } - command.append(runtimeConfig.command); - args.append(command); - spec["args"] = std::move(args); - spec["cwd"] = getWorkingDir(config, runtimeConfig); - if (shouldEnableGpu(config)) - { - Json::Value gpuObj(Json::objectValue); - gpuObj["enable"] = true; - gpuObj["memLimit"] = getGPUMemoryLimit(config, runtimeConfig); - spec["gpu"] = std::move(gpuObj); - } - spec["restartOnCrash"] = false; - - Json::Value vpuObj; - vpuObj["enable"] = getVpuEnabled(config, runtimeConfig); - spec["vpu"] = std::move(vpuObj); - - //TODO CHECK FOR OPTIMIZATION - std::list dbusRequiringApps = mAIConfiguration->getAppsRequiringDBus(); - for (auto it = dbusRequiringApps.begin(); it != dbusRequiringApps.end(); ++it) - { - std::string appId = *it; - if (appId.compare(config.mAppId) == 0) - { - Json::Value dbusObj(Json::objectValue); - dbusObj["system"] = "system"; - spec["dbus"] = std::move(dbusObj); - } - } - Json::Value cpuObj; - cpuObj["cores"] = getCpuCores(); - spec["cpu"] = std::move(cpuObj); - -#if (AI_BUILD_TYPE == AI_DEBUG) - Json::Value consoleObj; - consoleObj["limit"] = mAIConfiguration->getContainerConsoleLogCap(); - //TODO: SUPPORT Read console path from runtime config: RDKEMW-4432 - consoleObj["path"] = "/tmp/container.log"; - spec["console"] = std::move(consoleObj); -#endif // (AI_BUILD_TYPE == AI_DEBUG) - - Json::Value etcObj; - Json::Value hostsArray(Json::arrayValue); - Json::Value servicesArray(Json::arrayValue); - // always add a local host entry - hostsArray.append("127.0.0.1\tlocalhost"); - - // add some common services for the app - servicesArray.append("ftp\t\t21/tcp"); - servicesArray.append("domain\t\t53/tcp"); - servicesArray.append("domain\t\t53/udp"); - servicesArray.append("http\t\t80/tcp\t\twww"); - servicesArray.append("http\t\t80/udp"); - servicesArray.append("ntp\t\t123/udp"); - servicesArray.append("https\t\t443/tcp"); - servicesArray.append("https\t\t443/udp"); - - //TODO SUPPORT mapi in runtime config: RDKEMW-4432 - //if (runtimeConfig.mapi) - if (true) - { - for (int port : mAIConfiguration->getMapiPorts()) - { - servicesArray.append("mapi\t\t" + std::to_string(port) + "/tcp"); - } - } - - Json::Value preloadsArray(Json::arrayValue); - //TODO CHECK FOR OPTIMIZATION - std::list preloads = mAIConfiguration->getPreloads(); - for (auto it = preloads.begin(); it != preloads.end(); ++it) - { - preloadsArray.append(*it); - } - - etcObj["hosts"] = hostsArray; - etcObj["services"] = servicesArray; - etcObj["ld-preload"] = preloadsArray; - spec["etc"] = std::move(etcObj); - - if (runtimeConfig.wanLanAccess) - { - spec["network"] = "nat"; - } - else - { - spec["network"] = "private"; - } - Json::Value userObj; - userObj["uid"] = config.mUserId; - userObj["gid"] = config.mGroupId; - spec["user"] = std::move(userObj); - - //spec["plugins"] = populateClassicPlugins(config, runtimeConfig); - populateClassicPlugins(config, runtimeConfig, spec); - spec["rdkPlugins"] = createRdkPlugins(config, runtimeConfig); - spec["mounts"] = createMounts(config, runtimeConfig); - spec["env"] = createEnvVars(config, runtimeConfig); - -#ifdef RDK_APPMANAGERS_DEBUG - addHolePunchPortToSpec(spec, 22222); -#endif - - Json::FastWriter writer; - resultSpec = writer.write(spec); - LOGINFO("spec: '%s'\n", resultSpec.c_str()); - - std::ofstream generatedSpecFile; - generatedSpecFile.open("/tmp/generatedSpec.json"); - generatedSpecFile << resultSpec.c_str(); - generatedSpecFile.close(); - - return true; -} - -Json::Value DobbySpecGenerator::createEnvVars(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value env(Json::arrayValue); - env.append(std::string("APPLICATION_NAME=") + config.mAppId); - - //TODO YET TO ANALYZE SUPPORT APPLICATION_LAUNCH_PARAMETERS - //TODO YET TO ANALYZE SUPPORT APPLICATION_LAUNCH_METHOD - //TODO YET TO ANALYZE SUPPORT APPLICATION_TOKEN - - JsonArray envInputArray; - envInputArray.FromString(runtimeConfig.envVariables); - for (unsigned int i = 0; i < envInputArray.Length(); ++i) - { - std::string envInputItem = envInputArray[i].String(); - env.append(envInputArray[i].String()); - } - - std::list configEnvs = mAIConfiguration->getEnvs(); - for (auto it = configEnvs.begin(); it != configEnvs.end(); ++it) - { - env.append(*it); - } - - if (!config.mWesterosSocketPath.empty()) - { - env.append("XDG_RUNTIME_DIR=/tmp"); - env.append("WAYLAND_DISPLAY=westeros"); - env.append("WESTEROS_SINK_VIRTUAL_WIDTH=1920"); - env.append("WESTEROS_SINK_VIRTUAL_HEIGHT=1080"); - env.append("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=wayland-egl"); - env.append("QT_WAYLAND_SHELL_INTEGRATION=wl-simple-shell"); - env.append("QT_WAYLAND_INPUTDEVICE_INTEGRATION=skyq-input"); - env.append("QT_QPA_PLATFORM=wayland-sky-rdk"); - } - if (mAIConfiguration->getResourceManagerClientEnabled()) - { - env.append("ESSRMGR_APPID=" + config.mAppId); - env.append("CLIENT_IDENTIFIER=" + config.mAppId); - if (!config.mWesterosSocketPath.empty()) - { - env.append("WESTEROS_SINK_USE_ESSRMGR=1"); - } - } - - if (runtimeConfig.dial) - { - std::string dialId = runtimeConfig.dialId; - env.append(std::string("APPLICATION_DIAL_NAME=") + dialId); - std::ostringstream dataUrlStream; - dataUrlStream << "http://127.0.0.1:" - << mAIConfiguration->getDialServerPort() << '/' - << mAIConfiguration->getDialServerPathPrefix() << '/' - << dialId << '/' - << "dial_data"; - - std::string dataUrl = encodeURL(dataUrlStream.str()); - env.append(std::string("ADDITIONAL_DATA_URL=") + dataUrl); - env.append(std::string("DIAL_USN=") + mAIConfiguration->getDialUsn()); - } - - //TODO SUPPORT RIALTO - //TODO SUPPORT rialto in runtime config - //if (rialtoSMClient && appPackage->hasCapability(IPackage::Capability::RequiresRialto)) - if (false) - { - //const std::string rialtoSocketPath = rialtoSMClient->getSocketPath(); - //if (!rialtoSocketPath.empty()) - //{ - // // Pass Rialto socket name used by RialtoClient to communicate with RialtoSessionServer - // env.append(std::string("RIALTO_SOCKET_PATH=") + rialtoSocketPath); - //} - } - else if (!mGstRegistrySourcePath.empty()) - { - env.append("GST_REGISTRY=" + mGstRegistryDestinationPath); - env.append("GST_REGISTRY_UPDATE=no"); - } - - //TODO SUPPORT WATCHDOG - //TODO SUPPORT runtime parameter in runtime config: RDKEMW-4432 - //TODO SUPPORT Add only for web runtime - env.append("WEBKIT_LEGACY_INSPECTOR_SERVER=0.0.0.0:22222"); - - return env; -} - -Json::Value DobbySpecGenerator::createMounts(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value mounts(Json::arrayValue); - - if (!runtimeConfig.appPath.empty()) - { - mounts.append(createBindMount(runtimeConfig.appPath, mPackageMountPoint, MS_BIND | MS_RDONLY | MS_NOSUID | MS_NODEV)); - } - - if (!runtimeConfig.runtimePath.empty()) - { - mounts.append(createBindMount(runtimeConfig.runtimePath, mRuntimeMountPoint, MS_BIND | MS_RDONLY | MS_NOSUID | MS_NODEV)); - } - - mounts.append(createBindMount("/etc/ssl/certs", "/etc/ssl/certs", - (MS_BIND | MS_RDONLY | MS_NOSUID | MS_NODEV))); - - mounts.append(createPrivateDataMount(runtimeConfig)); - - createFkpsMounts(config, runtimeConfig, mounts); - - if (!config.mWesterosSocketPath.empty()) - { - if (mAIConfiguration->getResourceManagerClientEnabled()) - { - // bind mount the resource manager socket into the container - Json::Value resmgrMount = createResourceManagerMount(config); - if (!resmgrMount.isNull()) - mounts.append(std::move(resmgrMount)); - } - } - - //TODO SUPPORT Handle rialto - //TODO SUPPORT Netflix specific mounts - //TODO SUPPORT SVP file mounts - //TODO SUPPORT Platform specific mounts - //TODO SUPPORT Airplay specific mounts - //TODO SUPPORT TSB Storage - //TODO SUPPORT EPG specific migration data store mount - //TODO SUPPORT USB Mass storage - //TODO SUPPORT PerfettoSocketPath not mounted - /* - if (usingRialto) - { - Json::Value rialtoMount = createRialtoMount(appPackage, rialtoSMClient); - if (!rialtoMount.isNull()) - mountsArray.append(std::move(rialtoMount)); - } - */ - if (!mGstRegistrySourcePath.empty()) - { - mounts.append(createBindMount(mGstRegistrySourcePath, - mGstRegistryDestinationPath, - (MS_BIND | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY))); - } - - - return mounts; -} - -Json::Value DobbySpecGenerator::createBindMount(const std::string& source, - const std::string& destination, - unsigned long mountFlags) const -{ - Json::Value mount(Json::objectValue); - - mount["source"] = source; - mount["destination"] = destination; - mount["type"] = "bind"; - - Json::Value mountOptions(Json::arrayValue);; - - static const std::vector> mountFlagsNames = - { - { MS_BIND | MS_REC, "rbind" }, - { MS_BIND, "bind" }, - { MS_SILENT, "silent" }, - { MS_RDONLY, "ro" }, - { MS_SYNCHRONOUS, "sync" }, - { MS_NOSUID, "nosuid" }, - { MS_DIRSYNC, "dirsync" }, - { MS_NODIRATIME, "nodiratime" }, - { MS_RELATIME, "relatime" }, - { MS_NOEXEC, "noexec" }, - { MS_NODEV, "nodev" }, - { MS_NOATIME, "noatime" }, - { MS_STRICTATIME, "strictatime" }, - }; - - // convert the mount flags to their string equivalents - for (const auto &entry : mountFlagsNames) - { - const unsigned long mountFlag = entry.first; - if ((mountFlag & mountFlags) == mountFlag) - { - mountOptions.append(entry.second); - - // clear the mount flags bit such that we can display a warning - // if the caller supplies a flag we don't support - mountFlags &= ~mountFlag; - } - } - - // if there was a mount flag we didn't support display a warning - if (mountFlags != 0) - { - LOGWARN("unsupported mount flag(s) 0x%04lx", mountFlags); - } - - mount["options"] = std::move(mountOptions); - - return mount; -} - -bool DobbySpecGenerator::shouldEnableGpu(const ApplicationConfiguration& config) const -{ - return !config.mWesterosSocketPath.empty(); -} - -ssize_t DobbySpecGenerator::getSysMemoryLimit(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - ssize_t memoryLimit = runtimeConfig.systemMemoryLimit; - if (memoryLimit <= 0) - { - if (runtimeConfig.appType.compare("INTERACTIVE") == 0) - { - memoryLimit = mAIConfiguration->getNonHomeAppMemoryLimit(); - } - //TODO SUPPORT Add other application types - } - return memoryLimit; -} - -ssize_t DobbySpecGenerator::getGPUMemoryLimit(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - ssize_t gpuMemoryLimit = runtimeConfig.gpuMemoryLimit; - if (gpuMemoryLimit <= 0) - { - if (runtimeConfig.appType.compare("INTERACTIVE") == 0) - { - gpuMemoryLimit = mAIConfiguration->getNonHomeAppGpuLimit(); - } - //TODO SUPPORT Add other application types - } - return gpuMemoryLimit; -} - -bool DobbySpecGenerator::getVpuEnabled(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - // TODO SUPPORT RIALTO - /* - if (rialToEnabled) - { - return false; - } - */ - if (runtimeConfig.appType.compare("SYSTEM") == 0) - { - return false; - } - std::list vpuAccessBlackList = mAIConfiguration->getVpuAccessBlacklist(); - bool isBlackListed = false; - for (auto it = vpuAccessBlackList.begin(); it != vpuAccessBlackList.end(); ++it) - { - if ((*it).compare(config.mAppId) == 0) - { - isBlackListed = true; - break; - } - } - return !isBlackListed; -} - -std::string DobbySpecGenerator::getCpuCores() -{ - const int nCores = std::min(32, get_nprocs()); - std::bitset<32> cpuSetBitmask = mAIConfiguration->getAppsCpuSet(); - cpuSetBitmask &= ((0x1U << nCores) - 1); - // check the bitmask so that we have at least one core enabled - if (cpuSetBitmask.none()) - { - cpuSetBitmask = ((0x1U << nCores) - 1); - } - - // create the json string for the cores to enable - std::ostringstream coresStream; - for (int core = 0; core < nCores; core++) - { - if (cpuSetBitmask.test(core)) - { - coresStream << core << ","; - } - } - - // get the string and remove trailing ',' - std::string coresStr = coresStream.str(); - if (!coresStr.empty()) - coresStr.pop_back(); - - return coresStr; -} - -Json::Value DobbySpecGenerator::createRdkPlugins(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value rdkPluginsObj(Json::objectValue); - if (!config.mPorts.empty()) - { - rdkPluginsObj["appservicesrdk"] = createAppServiceSDKPlugin(config, runtimeConfig); - } - rdkPluginsObj["ionmemory"] = createIonMemoryPlugin(); - - - - rdkPluginsObj["networking"] = createNetworkPlugin(config, runtimeConfig); - if (runtimeConfig.thunder) - { - rdkPluginsObj["thunder"] = createThunderPlugin(config); - } - - //WORK: runtime config need to have credmgr certificate - /* - std::optional credmgrCert = appPackage->credmgrCertificate(); - if (credmgrCert) - { - rdkPluginsObj["credentialsmanager"]["data"] = - createCredentialsManagerData(credmgrCert->x509Certificate, credmgrCert->rsaKey); - } - */ - rdkPluginsObj["minidump"] = createMinidumpPlugin(); - - //WORK: httpproxy only for debug builds - /* - if (!mHttpProxyHostname.empty()) - { - rdkPluginsObj["httpproxy"] = createHttpProxyPlugin(false, - mHttpProxyHostname, - mHttpProxyPort, - mHttpProxyCACert); - } - */ - //WORK: seccomp - return rdkPluginsObj; -} - -Json::Value DobbySpecGenerator::createMinidumpPlugin() const -{ - Json::Value pluginObj(Json::objectValue); - static const Json::StaticString minidumpPath("/opt/minidumps"); - static const Json::StaticString minidumpSecurePath("/opt/secure/minidumps"); - - pluginObj["required"] = false; - if (access("/tmp/.SecureDumpDisable", R_OK) == 0) - { - pluginObj["data"]["destinationPath"] = minidumpPath; - } - else - { - pluginObj["data"]["destinationPath"] = minidumpSecurePath; - } - return pluginObj; -} - -//TODO SUPPORT localservices in appsservice plugin -//TODO SUPPORT airplay2 ports in appsservice plugin -Json::Value DobbySpecGenerator::createAppServiceSDKPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value pluginObj(Json::objectValue); - - pluginObj["required"] = false; - - Json::Value dependencies(Json::arrayValue); - dependencies.append("networking"); - - pluginObj["dependsOn"] = std::move(dependencies); - - Json::Value ports(Json::arrayValue); - if (runtimeConfig.dial) - { - ports.append(mAIConfiguration->getDialServerPort()); - } - for (auto port : config.mPorts) - ports.append(port); - for (int port : mAIConfiguration->getMapiPorts()) - { - ports.append(port); - } - pluginObj["data"]["additionalPorts"] = std::move(ports); - - return pluginObj; -} - -Json::Value DobbySpecGenerator::createNetworkPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value pluginObj(Json::objectValue); - - pluginObj["required"] = true; - - Json::Value dataObj(Json::objectValue); - if (runtimeConfig.wanLanAccess) - { - dataObj["type"] = "nat"; - dataObj["dnsmasq"] = true; - } - else - { - dataObj["type"] = "none"; - dataObj["dnsmasq"] = false; - } - - dataObj["ipv4"] = true; - dataObj["ipv6"] = mAIConfiguration->getIPv6Enabled(); - - //TODO SUPPORT Nat holepunch - /* - // add NAT holepunch support if requested (only for non-html apps) - if (appPackage->hasCapability(IPackage::Capability::NatHolePunch) && - isAllowedHolePunch(appPackage)) - { - data["portForwarding"]["hostToContainer"] = createHolePunchArray(appPackage); - } - - //TODO SUPPORT Multicast forwarding - // add multicast forwarding - primarily used for netflix MDX - if (appPackage->hasCapability(IPackage::Capability::MulticastForward)) - { - data["multicastForwarding"] = createMulticastGroupsArray(appPackage); - } - - // TODO SUPPORT inter-container communication - if (appPackage->hasCapability(IPackage::Capability::LocalSocketServer) || - appPackage->hasCapability(IPackage::Capability::LocalSocketClient)) - { - Json::Value interContainerArray = createInterContainerArray(appPackage); - if (!interContainerArray.empty()) - { - data[interContainer] = std::move(interContainerArray); - } - } - */ - pluginObj["data"] = std::move(dataObj); - - return pluginObj; -} - -void DobbySpecGenerator::populateClassicPlugins(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, Json::Value& spec) -{ - Json::Value pluginsArray(Json::arrayValue); - // enable the logging plugin - pluginsArray.append(createEthanLogPlugin(config, runtimeConfig)); - - //TODO SUPPORT Runtime config need to have requiresDrm parameter - /* - if (!usingRialto) - { - if ((appPackage->hasCapability(IPackage::Capability::RequiresDrm)) || - (appPackage->runtime() == "application/html")) - { - pluginsArray.append(createOpenCDMPlugin(config, runtimeConfig)); - } - } - */ - pluginsArray.append(createOpenCDMPlugin(config, runtimeConfig)); - - //TODO SUPPORT Runtime config need to have multicastSocket, multicastForward,NatHolePunch capability parameter - /* - if (appPackage->hasCapability(IPackage::Capability::MulticastSocket)) - if (false) - { - pluginsArray.append(createMulticastSocketPlugin(config, runtimeConfig)); - } - } - - // add multicast forwarding - primarily used for netflix MDX - if (appPackage->hasCapability(IPackage::Capability::MulticastForward)) - { - pluginsArray.append(createMulticastForwarderPlugin(appPackage)); - } - - // add NAT holepunch support if requested (only for non-html apps) - if (appPackage->hasCapability(IPackage::Capability::NatHolePunch) && - isAllowedHolePunch(appPackage)) //(package->runtime() == "application/system") - { - pluginsArray.append(createHolePuncherPlugin(appPackage)); - } - */ - spec["plugins"] = std::move(pluginsArray); -} - -Json::Value DobbySpecGenerator::createEthanLogPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - Json::Value plugin(Json::objectValue); - static const Json::StaticString name("name"); - static const Json::StaticString data("data"); - static const Json::StaticString pluginName("EthanLog"); - - static const Json::StaticString loglevels("loglevels"); - static const Json::StaticString fatal("fatal"); - static const Json::StaticString error("error"); - static const Json::StaticString warning("warning"); - static const Json::StaticString milestone("milestone"); - static const Json::StaticString info("info"); - static const Json::StaticString debug("debug"); - - Json::Value levels(Json::arrayValue); - //TODO SUPPORT logging mask in runtime config: RDKEMW-4432 - /* - unsigned logMask = package->loggingMask(); - if (logMask & unsigned(IPackage::LogLevel::Default)) - logMask |= mDefaultLoggingMask; - - if (logMask & unsigned(IPackage::LogLevel::Fatal)) - levels.append(fatal); - if (logMask & unsigned(IPackage::LogLevel::Error)) - levels.append(error); - if (logMask & unsigned(IPackage::LogLevel::Warning)) - levels.append(warning); - if (logMask & unsigned(IPackage::LogLevel::Info)) - levels.append(info); - if (logMask & unsigned(IPackage::LogLevel::Debug)) - levels.append(debug); - if (logMask & unsigned(IPackage::LogLevel::Milestone)) - levels.append(milestone); - */ - levels.append(fatal); - levels.append(error); - levels.append(warning); - levels.append(info); - levels.append(debug); - levels.append(milestone); - - plugin[name] = pluginName; - plugin[data][loglevels] = levels; - - return plugin; -} - - -Json::Value DobbySpecGenerator::createMulticastSocketPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - //TODO SUPPORT multicast socket plugin - /* - static const Json::StaticString name("name"); - static const Json::StaticString data("data"); - static const Json::StaticString pluginName("MulticastSockets"); - - static const Json::StaticString serverSockets("serverSockets"); - static const Json::StaticString clientSockets("clientSockets"); - - Json::Value serverSocketsArray = createMulticastServerSocketArray(package); - Json::Value clientSocketsArray = createMulticastClientSocketArray(package); - - if (serverSocketsArray.empty() && clientSocketsArray.empty()) - { - return Json::Value::null; - } - - Json::Value plugin(Json::objectValue); - plugin[name] = pluginName; - if (!serverSocketsArray.empty()) - plugin[data][serverSockets] = std::move(serverSocketsArray); - if (!clientSocketsArray.empty()) - plugin[data][clientSockets] = std::move(clientSocketsArray); - - return plugin; - */ - return Json::Value::null; -} - -Json::Value DobbySpecGenerator::createIonMemoryPlugin() const -{ - Json::Value plugin(Json::objectValue); - static const Json::StaticString data("data"); - plugin[data] = mIonMemoryPluginData; - return plugin; -} - -Json::Value DobbySpecGenerator::createThunderPlugin(const ApplicationConfiguration& config) const -{ - static const Json::StaticString dependsOn("dependsOn"); - static const Json::StaticString bearerUrl("bearerUrl"); - static const Json::StaticString data("data"); - static const Json::StaticString localServices1("http://local-services-1.sky.com"); - static const Json::StaticString localServices2("http://local-services-2.sky.com"); - static const Json::StaticString localServices3("http://local-services-3.sky.com"); - static const Json::StaticString localServices4("http://local-services-4.sky.com"); - static const Json::StaticString localServices5("http://local-services-5.sky.com"); - - Json::Value plugin(Json::objectValue); - Json::Value dependencies(Json::arrayValue); - dependencies.append("networking"); - plugin[dependsOn] = std::move(dependencies); - - //TODO SUPPORT Runtime config to check for localservices1,localservices2,localservices3,localservices4 - /* - if (package->hasCapability(IPackage::Capability::LocalServices1)) - plugin[data][bearerUrl] = localServices1; - else if (package->hasCapability(IPackage::Capability::LocalServices2)) - plugin[data][bearerUrl] = localServices2; - else if (package->hasCapability(IPackage::Capability::LocalServices3)) - plugin[data][bearerUrl] = localServices3; - else if (package->hasCapability(IPackage::Capability::LocalServices4)) - plugin[data][bearerUrl] = localServices4; - else - plugin[data][bearerUrl] = localServices5; - */ - plugin[data][bearerUrl] = localServices2; - - return plugin; -} - -Json::Value DobbySpecGenerator::createOpenCDMPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - static const Json::StaticString name("name"); - static const Json::StaticString data("data"); - static const Json::StaticString pluginName("OpenCDM"); - - Json::Value plugin(Json::objectValue); - plugin[name] = pluginName; - plugin[data] = Json::Value::null; - - return plugin; -} - -void DobbySpecGenerator::initialiseIonHeapsJson() -{ - Json::Value heapsArray(Json::arrayValue); - for (const auto &heapQuota : mAIConfiguration->getIonHeapQuotas()) - { - Json::Value heapObject(Json::objectValue); - heapObject["name"] = heapQuota.first; - heapObject["limit"] = heapQuota.second; - - heapsArray.append(std::move(heapObject)); - } - - mIonMemoryPluginData["defaultLimit"] = mAIConfiguration->getIonHeapDefaultQuota(); - mIonMemoryPluginData["heaps"] = std::move(heapsArray); -} - -Json::Value DobbySpecGenerator::createPrivateDataMount(const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const -{ - static const Json::StaticString source("source"); - static const Json::StaticString destination("destination"); - static const Json::StaticString type("type"); - static const Json::StaticString loop("loop"); - static const Json::StaticString fstype("fstype"); - static const Json::StaticString ext4("ext4"); - static const Json::StaticString options("options"); - - static const Json::StaticString nosuid("nosuid"); - static const Json::StaticString nodev("nodev"); - static const Json::StaticString noexec("noexec"); - - Json::Value mount(Json::objectValue); - std::string sourcePath(runtimeConfig.unpackedPath); - if (sourcePath.empty()) - { - return Json::nullValue; - } - - mount[source] = sourcePath; - mount[destination] = "/home/private"; - mount[type] = loop; - mount[fstype] = ext4; - - Json::Value optionsArray(Json::arrayValue); - optionsArray.append(nosuid); - optionsArray.append(nodev); - optionsArray.append(noexec); - mount[options] = optionsArray; - - return mount; -} - -void DobbySpecGenerator::createFkpsMounts(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, Json::Value& spec) const -{ - std::list fkpsFiles; - JsonArray fkpsFilesArray; - fkpsFilesArray.FromString(runtimeConfig.fkpsFiles); - for (unsigned int i = 0; i < fkpsFilesArray.Length(); ++i) - { - fkpsFiles.push_back(fkpsFilesArray[i].String()); - } - if (fkpsFiles.empty()) - return; - - // iterate through the files and make sure they're accessible - const std::string fkpsPathPrefix("/opt/drm/"); - for (std::list::iterator it=fkpsFiles.begin(); it!=fkpsFiles.end(); ++it) - { - std::string fkpsFile = *it; - const std::string fkpsFilePath = fkpsPathPrefix + fkpsFile; - - // check if the file exists - struct stat details; - if (stat(fkpsFilePath.c_str(), &details) != 0) - { - if (errno == ENOENT) - { - printf("missing FKPS file '%s', won't map into container", - fkpsFilePath.c_str()); - } - else - { - printf("failed to set FKPS file '%s' %d", - fkpsFilePath.c_str(), errno); - } - - continue; - } - - // check the group owner matches the app - if ((details.st_gid != config.mGroupId) && - (chown(fkpsFilePath.c_str(), -1, config.mGroupId) != 0)) - { - printf("failed to change group owner of '%s' %d", - fkpsFilePath.c_str(), errno); - } - - // and that the group perms are set to r-- - if (((details.st_mode & S_IRGRP) != S_IRGRP) && - (chmod(fkpsFilePath.c_str(), ((details.st_mode | S_IRGRP) & ALLPERMS)) != 0)) - { - printf("failed to set file permissions to 0%03o for '%s' %d", - ((details.st_mode & ~S_IRWXG) | S_IRGRP), fkpsFilePath.c_str(), errno); - } - - // finally add a bind mount for them - spec.append(createBindMount(fkpsFilePath, fkpsFilePath, - (MS_BIND | MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC))); - } - - // additional tmpfs mount apparently required for YT certification - spec.append(createTmpfsMount("/opt/drm/vault", - (MS_NOSUID | MS_NODEV | MS_NOEXEC))); - -} - -Json::Value DobbySpecGenerator::createTmpfsMount(const std::string &mntDestination, - unsigned long mntOptions) const -{ - static const Json::StaticString source("source"); - static const Json::StaticString destination("destination"); - static const Json::StaticString type("type"); - static const Json::StaticString tmpfs("tmpfs"); - static const Json::StaticString options("options"); - - static const Json::StaticString nosuid("nosuid"); - static const Json::StaticString nodev("nodev"); - static const Json::StaticString noexec("noexec"); - static const Json::StaticString noatime("noatime"); - static const Json::StaticString relatime("relatime"); - static const Json::StaticString strictatime("strictatime"); - static const Json::StaticString sync("sync"); - static const Json::StaticString nodiratime("nodiratime"); - static const Json::StaticString size("size=65536k"); - static const Json::StaticString indoes("nr_inodes=8k"); - Json::Value mount(Json::objectValue); - - mount[type] = tmpfs; - mount[source] = tmpfs; - mount[destination] = mntDestination; - - Json::Value optionsArray(Json::arrayValue); - - if (mntOptions & MS_NOSUID) - optionsArray.append(nosuid); - if (mntOptions & MS_NODEV) - optionsArray.append(nodev); - if (mntOptions & MS_NOEXEC) - optionsArray.append(noexec); - - if (mntOptions & MS_SYNCHRONOUS) - optionsArray.append(sync); - - if (mntOptions & MS_NODIRATIME) - optionsArray.append(nodiratime); - - if (mntOptions & MS_NOATIME) - optionsArray.append(noatime); - if (mntOptions & MS_RELATIME) - optionsArray.append(relatime); - if (mntOptions & MS_STRICTATIME) - optionsArray.append(strictatime); - - optionsArray.append(size); - optionsArray.append(indoes); - - mount[options] = std::move(optionsArray); - - return mount; -} - -Json::Value DobbySpecGenerator::createResourceManagerMount(const ApplicationConfiguration& config) const -{ - constexpr unsigned long mntOptions = (MS_BIND | MS_NOSUID | MS_NODEV | MS_NOEXEC); - static const std::string resmgrMountSource = XDG_RUNTIME_DIR "/resource"; - static const std::string resmgrMountPoint = XDG_RUNTIME_DIR "/resource"; - - struct stat details; - Json::Value resmgrMount; - if (stat(resmgrMountSource.c_str(), &details) == 0) - { - resmgrMount = createBindMount(resmgrMountSource, resmgrMountPoint, mntOptions); - - // check the group owner matches the app - if ((details.st_gid != config.mGroupId) && - (chown(resmgrMountSource.c_str(), -1, config.mGroupId) != 0)) - { - printf("failed to change group owner of '%s'", resmgrMountSource.c_str()); - } - - // and that the group perms are set to 0770 - if (chmod(resmgrMountSource.c_str(), 0770) != 0) - { - printf("failed to set file permissions to 0770 for '%s'", resmgrMountSource.c_str()); - } - } - - return resmgrMount; -} - -std::string DobbySpecGenerator::encodeURL(std::string url) const -{ - std::string encodedUrl; - - CURL *curl = curl_easy_init(); - if (curl) - { - char *escapedUrl = curl_easy_escape(curl, url.c_str(), (int)url.length()); - if (escapedUrl) - { - encodedUrl = std::string(escapedUrl); - curl_free(escapedUrl); - } - else - { - printf("curl_easy_escape() failed"); - fflush(stdout); - } - - curl_easy_cleanup(curl); - } - else - { - printf("curl_easy_init() failed"); - fflush(stdout); - } - - return encodedUrl; -} - -void DobbySpecGenerator::addHolePunchPortToSpec(Json::Value &spec, in_port_t port) const -{ -printf("Adding hole punching port %hu for app", port); - fflush(stdout); - - static Json::Value nullValue(Json::nullValue); - - Json::Value &specRef = spec; - - // create a new entry - Json::Value entry(Json::objectValue); - entry["port"] = port; - entry["protocol"] = "tcp"; - - // check which type of spec we have - if (specRef.isMember("rdkPlugins")) - { - // dobby++ spec format - Json::Value &rdkPlugins = specRef["rdkPlugins"]; - - const Json::Value &hostToContainer = - Json::Path(".networking.data.portForwarding.hostToContainer") - .resolve(rdkPlugins); - if (!hostToContainer.isArray()) - { - // no hole punches defined so add Networking rdkPlugin's - // hostToContainer field - rdkPlugins["networking"]["data"]["portForwarding"]["hostToContainer"] = Json::arrayValue; - } - - // append to the array hole punches array - rdkPlugins["networking"]["data"]["portForwarding"]["hostToContainer"].append(std::move(entry)); - } - else - { - // classic dobby format - - // add / modify the hole punch code for gdbserver - Json::Value &plugins = specRef["plugins"]; - for (Json::Value &plugin : plugins) - { - if (!plugin.isObject()) - break; - - const Json::Value &name = plugin["name"]; - if (!name.isString() || (strcmp(name.asCString(), "HolePuncher") != 0)) - continue; - - Json::Value &holes = plugin["data"]["holes"]; - if (!holes.isArray()) - LOGINFO("odd, invalid HolePuncher plugin json object"); - else - holes.append(std::move(entry)); - - return; - } - - // no hole punch plugin defined so add one now - Json::Value holes(Json::arrayValue); - holes.append(std::move(entry)); - - Json::Value plugin(Json::objectValue); - plugin["name"] = "HolePuncher"; - plugin["data"]["holes"] = std::move(holes); - - plugins.append(std::move(plugin)); - } -} -} // namespace Plugin -} // namespace WPEFramework diff --git a/RuntimeManager/DobbySpecGenerator.h b/RuntimeManager/DobbySpecGenerator.h deleted file mode 100644 index f5168be..0000000 --- a/RuntimeManager/DobbySpecGenerator.h +++ /dev/null @@ -1,88 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -// using jsoncpp instead of Thunders code::json, because of slash escaping. -// In core::json "/path" will be serialized to either "\/path" (normal case) -// or just path (without quotation, if quotation disabled using path.SetQuoted(false)) -#include -#include "tracing/Logging.h" -#include -#include "ApplicationConfiguration.h" -#include -#include "AIConfiguration.h" - -namespace WPEFramework -{ -namespace Plugin -{ - -// struct ApplicationConfiguration; - - class DobbySpecGenerator - { - public: - DobbySpecGenerator(); - virtual ~DobbySpecGenerator(); - - bool generate(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, string& outputJsonString); - - private: - Json::Value createEnvVars(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createMounts(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createRdkPlugins(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createMinidumpPlugin() const; - Json::Value createAppServiceSDKPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createNetworkPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createBindMount(const std::string &source, - const std::string &destination, - unsigned long options) const; - - bool shouldEnableGpu(const ApplicationConfiguration& config) const; - - ssize_t getSysMemoryLimit(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - ssize_t getGPUMemoryLimit(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - bool getVpuEnabled(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - std::string getCpuCores(); - void populateClassicPlugins(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, Json::Value& spec); - Json::Value createEthanLogPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createMulticastSocketPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createIonMemoryPlugin() const; - Json::Value createThunderPlugin(const ApplicationConfiguration& config) const; - Json::Value createOpenCDMPlugin(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - Json::Value createPrivateDataMount(const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - void createFkpsMounts(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, Json::Value& spec) const; - Json::Value createTmpfsMount(const std::string &mntDestination, - unsigned long mntOptions) const; - Json::Value createResourceManagerMount(const ApplicationConfiguration& config) const; - Json::Value getWorkingDir(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig) const; - void initialiseIonHeapsJson(); - std::string encodeURL(std::string url) const; - void addHolePunchPortToSpec(Json::Value &spec, in_port_t port) const; - - Json::Value mIonMemoryPluginData; - std::string mPackageMountPoint; - std::string mRuntimeMountPoint; - std::string mGstRegistrySourcePath; - std::string mGstRegistryDestinationPath; - AIConfiguration* mAIConfiguration; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/IEventHandler.h b/RuntimeManager/IEventHandler.h deleted file mode 100644 index 1b6bfba..0000000 --- a/RuntimeManager/IEventHandler.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include -#include - - -namespace WPEFramework -{ - namespace Plugin - { - class IEventHandler - { - public: - virtual void onOCIContainerStartedEvent(std::string name, JsonObject& data) = 0; - virtual void onOCIContainerStoppedEvent(std::string name, JsonObject& data) = 0; - virtual void onOCIContainerFailureEvent(std::string name, JsonObject& data) = 0; - virtual void onOCIContainerStateChangedEvent(std::string name, JsonObject& data) = 0; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ \ No newline at end of file diff --git a/RuntimeManager/Module.cpp b/RuntimeManager/Module.cpp deleted file mode 100644 index cd6d4d1..0000000 --- a/RuntimeManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/RuntimeManager/Module.h b/RuntimeManager/Module.h deleted file mode 100755 index bbc09fa..0000000 --- a/RuntimeManager/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_RuntimeManager -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/RuntimeManager/README.md b/RuntimeManager/README.md deleted file mode 100755 index b988ae2..0000000 --- a/RuntimeManager/README.md +++ /dev/null @@ -1,18 +0,0 @@ ------------------ -# RuntimeManager - -## Versions -`org.rdk.RuntimeManager.1` - -## Methods: -``` -``` - -## Responses -``` -``` - -## Events -``` -none -``` diff --git a/RuntimeManager/RialtoConnector.cpp b/RuntimeManager/RialtoConnector.cpp deleted file mode 100644 index cc46a68..0000000 --- a/RuntimeManager/RialtoConnector.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "RialtoConnector.h" - - -namespace WPEFramework -{ - void RialtoConnector::initialize() - { - if (!mInitialized) - { - WPEFramework::Plugin::AIConfiguration* mAIConfiguration; - LOGWARN("Initializing rialto connector.... Rialto Bridge version 1.1"); - firebolt::rialto::common::ServerManagerConfig config; - mAIConfiguration = new WPEFramework::Plugin::AIConfiguration(); - mAIConfiguration->initialize(); - config.sessionServerEnvVars = mAIConfiguration->getEnvs(); - mServerManagerService = create(shared_from_this(), config); - mInitialized = true; - delete mAIConfiguration; - } - } - bool RialtoConnector::createAppSession(const std::string &callsign, const std::string &displayName, const std::string &appId) - { - LOGINFO("Creating app session with callsign : '%s', display name : '%s', appid : '%s'", callsign.c_str(), displayName.c_str(), appId.c_str()); - if (!callsign.empty() && !displayName.empty() && ! appId.empty()) - { - firebolt::rialto::common::AppConfig config = {appId, displayName}; - return mServerManagerService ->initiateApplication(callsign, - RialtoServerStates::ACTIVE, - config); - } - else - { - LOGERR("Create app session failed.."); - return false; - } - } - bool RialtoConnector::resumeSession(const std::string &callsign) - { - if (RialtoServerStates::INACTIVE == getCurrentAppState(callsign)) - return mServerManagerService ->changeSessionServerState(callsign, - RialtoServerStates::ACTIVE); - return false; - } - bool RialtoConnector::suspendSession(const std::string &callsign) - { - if (RialtoServerStates::ACTIVE == getCurrentAppState(callsign)) - return mServerManagerService ->changeSessionServerState(callsign, - RialtoServerStates::INACTIVE); - return false; - } - const RialtoServerStates RialtoConnector::getCurrentAppState(const std::string &callsign) - { - auto state = appStateMap.find(callsign); - if (state != appStateMap.end()) - { - // If the state is not inactive, we have a problem. - return state->second; - } - return RialtoServerStates::ERROR; - } - bool RialtoConnector::deactivateSession(const std::string &callsign) - { - LOGINFO("Deactiving app %s", callsign.c_str()); - RialtoServerStates state = getCurrentAppState(callsign); - if (RialtoServerStates::ACTIVE == state || - RialtoServerStates::INACTIVE == state) - return mServerManagerService ->changeSessionServerState(callsign, - RialtoServerStates::NOT_RUNNING); - LOGINFO("Rialto server is not in active or running state. "); - return false; - } - void RialtoConnector::stateChanged(const std::string &appId, - const RialtoServerStates &state) - { - { - std::lock_guard lockguard(m_stateMutex); - appStateMap[appId] = state; - } - LOGINFO("[RialtoConnector::stateChanged] State change announced for %s to %d, isActive ? %d ", appId.c_str(), - static_cast(state), (state == RialtoServerStates::ACTIVE)); - m_stateCond.notify_one(); - } - - // wait until socket is in given state - // return true when state set, false on timeout - bool RialtoConnector::waitForStateChange(const std::string& appId, const RialtoServerStates& state, int timeoutMillis) - { - bool status = false; - std::unique_lock lock(m_stateMutex); - auto startTime = std::chrono::steady_clock::now(); - auto endTime = startTime + std::chrono::milliseconds(timeoutMillis); - - while (std::chrono::steady_clock::now() < endTime) - { - if (appStateMap[appId] == state) - { - status = true; - break; - } - - auto remainingTime = std::chrono::duration_cast(endTime - std::chrono::steady_clock::now()); - if (remainingTime.count() <= 0) - break; - - m_stateCond.wait_for(lock, remainingTime); - } - - return status; - } -} // namespace WPEFramework diff --git a/RuntimeManager/RialtoConnector.h b/RuntimeManager/RialtoConnector.h deleted file mode 100644 index 2c76398..0000000 --- a/RuntimeManager/RialtoConnector.h +++ /dev/null @@ -1,64 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include "UtilsLogging.h" -#include -#include -#include -#include -#include "rialto/ServerManagerServiceFactory.h" - -#include "AIConfiguration.h" -namespace WPEFramework -{ - using namespace rialto::servermanager::service; - // Shadowing to keep Rialto contained in this - typedef firebolt::rialto::common::SessionServerState RialtoServerStates; - - class RialtoConnector : public IStateObserver, public std::enable_shared_from_this - { - public: - RialtoConnector() : mInitialized(false) {} - virtual ~RialtoConnector() = default; - void initialize(); - bool waitForStateChange(const std::string &appid, const RialtoServerStates &state, int timeoutMillis); - bool createAppSession(const std::string &callsign, const std::string &displayName, const std::string &appId); - bool resumeSession(const std::string &callsign); - bool suspendSession(const std::string &callsign); - - bool deactivateSession(const std::string &callsign); - void stateChanged(const std::string &appId, const RialtoServerStates &state) override; - - RialtoConnector(const RialtoConnector &) = delete; // No copying - RialtoConnector &operator=(const RialtoConnector &) = delete; // No assignment - - private: - bool mInitialized; - std::mutex m_stateMutex; - std::condition_variable m_stateCond; - std::unique_ptr mServerManagerService ; - std::map appStateMap; - - const RialtoServerStates getCurrentAppState(const std::string &callsign); - - }; -} // namespace WPEFramework diff --git a/RuntimeManager/RuntimeManager.conf.in b/RuntimeManager/RuntimeManager.conf.in deleted file mode 100644 index b2e433a..0000000 --- a/RuntimeManager/RuntimeManager.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.RuntimeManager" -autostart = "@PLUGIN_RUNTIME_MANAGER_AUTOSTART@" -startuporder = "@PLUGIN_RUNTIME_MANAGER_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_RUNTIME_MANAGER_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) -configuration.add("runtimeAppPortal","@PLUGIN_RUNTIME_APP_PORTAL@") diff --git a/RuntimeManager/RuntimeManager.config b/RuntimeManager/RuntimeManager.config deleted file mode 100644 index d2f69ea..0000000 --- a/RuntimeManager/RuntimeManager.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart ${PLUGIN_RUNTIME_MANAGER_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.RuntimeManager") - -if(PLUGIN_RUNTIME_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_RUNTIME_MANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_RUNTIME_MANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) \ No newline at end of file diff --git a/RuntimeManager/RuntimeManager.cpp b/RuntimeManager/RuntimeManager.cpp deleted file mode 100644 index 345540f..0000000 --- a/RuntimeManager/RuntimeManager.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "RuntimeManager.h" - -const string WPEFramework::Plugin::RuntimeManager::SERVICE_NAME = "org.rdk.RuntimeManager"; - -namespace WPEFramework -{ - namespace { - - static Plugin::Metadata metadata( - /* Version (Major, Minor, Patch) */ - RUNTIME_MANAGER_API_VERSION_NUMBER_MAJOR, RUNTIME_MANAGER_API_VERSION_NUMBER_MINOR, RUNTIME_MANAGER_API_VERSION_NUMBER_PATCH, - /* Preconditions */ - {}, - /* Terminations */ - {}, - /* Controls */ - {} - ); - } - - namespace Plugin - { - - SERVICE_REGISTRATION(RuntimeManager, RUNTIME_MANAGER_API_VERSION_NUMBER_MAJOR, RUNTIME_MANAGER_API_VERSION_NUMBER_MINOR, RUNTIME_MANAGER_API_VERSION_NUMBER_PATCH); - - RuntimeManager* RuntimeManager::sInstance = nullptr; - - RuntimeManager::RuntimeManager(): - mCurrentService(nullptr), - mConnectionId(0), - mRuntimeManagerImpl(nullptr), - mRuntimeManagerConfigure(nullptr) - { - SYSLOG(Logging::Startup, (_T("RuntimeManager Constructor"))); - RuntimeManager::sInstance = this; - } - - RuntimeManager::~RuntimeManager() - { - SYSLOG(Logging::Startup, (_T("RuntimeManager Destructor"))); - RuntimeManager::sInstance = nullptr; - } - - const string RuntimeManager::Initialize(PluginHost::IShell* service ) - { - string retMessage = ""; - - ASSERT(nullptr != service); - ASSERT(0 == mConnectionId); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mRuntimeManagerImpl); - - SYSLOG(Logging::Startup, (_T("RuntimeManager::Initialize: PID=%u"), getpid())); - mCurrentService = service; - - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - - if (nullptr == (mRuntimeManagerImpl = mCurrentService->Root(mConnectionId, 5000, _T("RuntimeManagerImplementation")))) - { - SYSLOG(Logging::Startup, (_T("RuntimeManager::Initialize: object creation failed"))); - retMessage = _T("RuntimeManager plugin could not be initialised"); - } - else if (nullptr == (mRuntimeManagerConfigure = mRuntimeManagerImpl->QueryInterface())) - { - SYSLOG(Logging::Startup, (_T("RuntimeManager::Initialize: did not provide a configuration interface"))); - retMessage = _T("RuntimeManager implementation did not provide a configuration interface"); - } - else - { - if (Core::ERROR_NONE != mRuntimeManagerConfigure->Configure(mCurrentService)) - { - SYSLOG(Logging::Startup, (_T("RuntimeManager::Initialize: could not be configured"))); - retMessage = _T("RuntimeManager could not be configured"); - } - } - } - else - { - SYSLOG(Logging::Startup, (_T("RuntimeManager::Initialize: service is not valid"))); - retMessage = _T("RuntimeManager plugin could not be initialised"); - } - - if (0 != retMessage.length()) - { - Deinitialize(service); - } - - return retMessage; - } - - void RuntimeManager::Deinitialize(PluginHost::IShell* service) - { - ASSERT(mCurrentService == service); - - SYSLOG(Logging::Shutdown, (string(_T("RuntimeManager::Deinitialize")))); - - if (nullptr != mRuntimeManagerImpl) - { - if (nullptr != mRuntimeManagerConfigure) - { - mRuntimeManagerConfigure->Release(); - mRuntimeManagerConfigure = nullptr; - } - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mRuntimeManagerImpl->Release(); - - mRuntimeManagerImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mCurrentService->Release(); - mCurrentService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("RuntimeManager de-initialised")))); - } - - string RuntimeManager::Information() const - { - return(string("{\"service\": \"") + SERVICE_NAME + string("\"}")); - } - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/RuntimeManager.h b/RuntimeManager/RuntimeManager.h deleted file mode 100644 index dbd5e19..0000000 --- a/RuntimeManager/RuntimeManager.h +++ /dev/null @@ -1,64 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" - -namespace WPEFramework -{ - namespace Plugin - { - class RuntimeManager : public PluginHost::IPlugin - { - public: - RuntimeManager(const RuntimeManager&) = delete; - RuntimeManager& operator=(const RuntimeManager&) = delete; - - RuntimeManager(); - virtual ~RuntimeManager(); - - BEGIN_INTERFACE_MAP(RuntimeManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_AGGREGATE(Exchange::IRuntimeManager, mRuntimeManagerImpl) - END_INTERFACE_MAP - - /* IPlugin methods */ - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - public /* constants */: - static const string SERVICE_NAME; - - public /* members */: - static RuntimeManager* sInstance; - - private: /* members */ - PluginHost::IShell* mCurrentService{}; - uint32_t mConnectionId; - Exchange::IRuntimeManager* mRuntimeManagerImpl; - Exchange::IConfiguration* mRuntimeManagerConfigure; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/RuntimeManagerImplementation.cpp b/RuntimeManager/RuntimeManagerImplementation.cpp deleted file mode 100755 index fb73ebd..0000000 --- a/RuntimeManager/RuntimeManagerImplementation.cpp +++ /dev/null @@ -1,1293 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "RuntimeManagerImplementation.h" -#include "DobbySpecGenerator.h" -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - SERVICE_REGISTRATION(RuntimeManagerImplementation, 1, 0); - RuntimeManagerImplementation* RuntimeManagerImplementation::_instance = nullptr; - - RuntimeManagerImplementation::RuntimeManagerImplementation() - : mRuntimeManagerImplLock() - , mCurrentservice(nullptr) - , mOciContainerObject(nullptr) - , mStorageManagerObject(nullptr) - , mWindowManagerConnector(nullptr) - , mDobbyEventListener(nullptr) - , mUserIdManager(nullptr) - , mRuntimeAppPortal("") -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - , mTelemetryMetricsObject(nullptr) -#endif - { - LOGINFO("Create RuntimeManagerImplementation Instance"); - if (nullptr == RuntimeManagerImplementation::_instance) - { - RuntimeManagerImplementation::_instance = this; - } -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED - LOGWARN("Creating rialto connector"); - RialtoConnector *rialtoBridge = new RialtoConnector(); - mRialtoConnector = std::shared_ptr(rialtoBridge); -#endif // RIALTO_IN_DAC_FEATURE_ENABLED - } - - RuntimeManagerImplementation* RuntimeManagerImplementation::getInstance() - { - return _instance; - } - - RuntimeManagerImplementation::~RuntimeManagerImplementation() - { - LOGINFO("Call RuntimeManagerImplementation destructor"); - - if (nullptr != mCurrentservice) - { - mCurrentservice->Release(); - mCurrentservice = nullptr; - } - - if (nullptr != mStorageManagerObject) - { - releaseStorageManagerPluginObject(); - } - - - if (nullptr != mWindowManagerConnector) - { - mWindowManagerConnector->releasePlugin(); - delete mWindowManagerConnector; - mWindowManagerConnector = nullptr; - } - - if (nullptr != mUserIdManager) - { - delete mUserIdManager; - mUserIdManager = nullptr; - } - - if(nullptr != mOciContainerObject) - { - releaseOCIContainerPluginObject(); - } - } - - Core::hresult RuntimeManagerImplementation::Register(Exchange::IRuntimeManager::INotification *notification) - { - ASSERT (nullptr != notification); - - Core::SafeSyncType lock(mRuntimeManagerImplLock); - - /* Make sure we can't register the same notification callback multiple times */ - if (std::find(mRuntimeManagerNotification.begin(), mRuntimeManagerNotification.end(), notification) == mRuntimeManagerNotification.end()) - { - LOGINFO("Register notification"); - mRuntimeManagerNotification.push_back(notification); - notification->AddRef(); - } - - return Core::ERROR_NONE; - } - - Core::hresult RuntimeManagerImplementation::Unregister(Exchange::IRuntimeManager::INotification *notification ) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - Core::SafeSyncType lock(mRuntimeManagerImplLock); - - /* Make sure we can't unregister the same notification callback multiple times */ - auto itr = std::find(mRuntimeManagerNotification.begin(), mRuntimeManagerNotification.end(), notification); - if (itr != mRuntimeManagerNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - mRuntimeManagerNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - return status; - } - - void RuntimeManagerImplementation::dispatchEvent(RuntimeEventType event, const JsonValue ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void RuntimeManagerImplementation::Dispatch(RuntimeEventType event, const JsonValue params) - { - Core::SafeSyncType lock(mRuntimeManagerImplLock); - - std::list::const_iterator index(mRuntimeManagerNotification.begin()); - - JsonObject obj = params.Object(); - string appIdFromContainer = obj["containerId"].String(); - if (!mRuntimeAppPortal.empty() && appIdFromContainer.find(mRuntimeAppPortal) == 0) // TODO improve logic of fetching appInstanceId - { - appIdFromContainer.erase(0, mRuntimeAppPortal.length()); - } - string appInstanceId = std::move(appIdFromContainer); - string eventName = obj["eventName"].String(); - LOGINFO("Dispatching event[%s] for appInstanceId[%s]", eventName.c_str(), appInstanceId.c_str()); - - switch (event) - { - case RUNTIME_MANAGER_EVENT_STATECHANGED: - while (index != mRuntimeManagerNotification.end()) - { - string containerState = obj["state"]; - int containerStateInt = std::stoi(containerState); - RuntimeState state = static_cast(containerStateInt); - LOGINFO("RuntimeManagerImplementation::Dispatch: state[%d]", state); - (*index)->OnStateChanged(appInstanceId, state); - ++index; - } - break; - - case RUNTIME_MANAGER_EVENT_CONTAINERSTARTED: - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - auto it = mRuntimeAppInfo.find(appInstanceId); - if (it != mRuntimeAppInfo.end()) - { - RuntimeAppInfo& appInfo = it->second; - - if (appInfo.requestType == REQUEST_TYPE_LAUNCH) - { - recordTelemetryData(TELEMETRY_MARKER_LAUNCH_TIME, appInfo.appId, appInfo.requestTime); - } - } - else - { - LOGERR("RuntimeAppInfo not found for appInstanceId: %s", appInstanceId.c_str()); - } -#endif - while (index != mRuntimeManagerNotification.end()) - { - (*index)->OnStarted(appInstanceId); - ++index; - } - break; - } - - case RUNTIME_MANAGER_EVENT_CONTAINERSTOPPED: - { -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - auto it = mRuntimeAppInfo.find(appInstanceId); - if (it != mRuntimeAppInfo.end()) - { - RuntimeAppInfo& appInfo = it->second; - if (appInfo.requestType == REQUEST_TYPE_TERMINATE || appInfo.requestType == REQUEST_TYPE_KILL) - { - recordTelemetryData(TELEMETRY_MARKER_CLOSE_TIME, appInfo.appId, appInfo.requestTime); - } - } - else - { - LOGERR("RuntimeAppInfo not found for appInstanceId: %s", appInstanceId.c_str()); - } -#endif - while (index != mRuntimeManagerNotification.end()) - { - (*index)->OnTerminated(appInstanceId); - ++index; - } - break; - } - - case RUNTIME_MANAGER_EVENT_CONTAINERFAILED: - while (index != mRuntimeManagerNotification.end()) - { - string error = obj["errorCode"].String(); - (*index)->OnFailure(appInstanceId, error); - ++index; - } - break; - - default: - LOGWARN("Event[%u] not handled", event); - break; - } - } - - uint32_t RuntimeManagerImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_GENERAL; - - if (service != nullptr) - { - Core::SafeSyncType lock(mRuntimeManagerImplLock); - - mCurrentservice = service; - mCurrentservice->AddRef(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (nullptr == (mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"))) - { - LOGERR("mTelemetryMetricsObject is null \n"); - } - else - { - LOGINFO("created TelemetryMetrics Object"); - } -#endif - /* Create Storage Manager Plugin Object */ - if (Core::ERROR_NONE != createStorageManagerPluginObject()) - { - LOGERR("Failed to create Storage Manager Object"); - } - - /* Create Window Manager Plugin Object */ - mWindowManagerConnector = new WindowManagerConnector(); - if (false == mWindowManagerConnector->initializePlugin(service)) - { - LOGERR("Failed to create Window Manager Connector Object"); - } - - mUserIdManager = new UserIdManager(); - - if (Core::ERROR_NONE != createOCIContainerPluginObject()) - { - LOGERR("Failed to create OCIContainerPluginObject"); - } - else - { - LOGINFO("created OCIContainerPluginObject"); - result = Core::ERROR_NONE; - } - RuntimeManagerImplementation::Configuration config; - config.FromString(service->ConfigLine()); - if (!config.runtimeAppPortal.Value().empty()) - { - mRuntimeAppPortal = config.runtimeAppPortal.Value(); - } - LOGINFO("runtimeAppPortal=%s", mRuntimeAppPortal.c_str()); - } - else - { - LOGERR("service is null"); - } - return result; - } - - - - Core::hresult RuntimeManagerImplementation::createOCIContainerPluginObject() - { - #define MAX_OCI_OBJECT_CREATION_RETRIES 2 - - Core::hresult status = Core::ERROR_GENERAL; - uint8_t retryCount = 0; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null"); - goto err_ret; - } - - do - { - mOciContainerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.OCIContainer"); - if (nullptr == mOciContainerObject) - { - LOGERR("mOciContainerObject is null (Attempt %d)", retryCount + 1); - retryCount++; - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - else - { - LOGINFO("Successfully created OCI Container Object"); - status = Core::ERROR_NONE; - /* Initialize OCIContainerNotification Connector to listen to Dobby Events */ - mDobbyEventListener = new DobbyEventListener(); - if(nullptr != mDobbyEventListener) - { - if (false == mDobbyEventListener->initialize(mCurrentservice, this, mOciContainerObject)) - { - LOGERR("Failed to initialize DobbyEventListener"); - } - break; - } - } - } while (retryCount < MAX_OCI_OBJECT_CREATION_RETRIES); - - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to create OCIContainer Object after %d attempts", MAX_OCI_OBJECT_CREATION_RETRIES); - } -err_ret: - return status; - } - - void RuntimeManagerImplementation::releaseOCIContainerPluginObject() - { - ASSERT(nullptr != mOciContainerObject); - if(mOciContainerObject) - { - LOGINFO("releaseOCIContainerPluginObject\n"); - /* Deinitialize DobbyEventListener */ - if (nullptr != mDobbyEventListener) - { - mDobbyEventListener->deinitialize(); - delete mDobbyEventListener; - mDobbyEventListener = nullptr; - } - mOciContainerObject->Release(); - mOciContainerObject = nullptr; - } - } - - Core::hresult RuntimeManagerImplementation::createStorageManagerPluginObject() - { - #define MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES 2 - - Core::hresult status = Core::ERROR_GENERAL; - uint8_t retryCount = 0; - - if (nullptr == mCurrentservice) - { - LOGERR("mCurrentservice is null"); - } - else - { - do - { - mStorageManagerObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.StorageManager"); - - if (nullptr == mStorageManagerObject) - { - LOGERR("storageManagerObject is null (Attempt %d)", retryCount + 1); - retryCount++; - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - else - { - LOGINFO("Successfully created Storage Manager Object"); - status = Core::ERROR_NONE; - break; - } - } while (retryCount < MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES); - - if (status != Core::ERROR_NONE) - { - LOGERR("Failed to create Storage Manager Object after %d attempts", MAX_STORAGE_MANAGER_OBJECT_CREATION_RETRIES); - } - } - return status; - } - - void RuntimeManagerImplementation::releaseStorageManagerPluginObject() - { - ASSERT(nullptr != mStorageManagerObject); - if(mStorageManagerObject) - { - LOGINFO("Storage Manager object released\n"); - mStorageManagerObject->Release(); - mStorageManagerObject = nullptr; - } - } - -/* -* @brief : Returns the storage information for a given app id using Storage Manager plugin interface -*/ - Core::hresult RuntimeManagerImplementation::getAppStorageInfo(const string& appId, AppStorageInfo& appStorageInfo) - { - Core::hresult status = Core::ERROR_GENERAL; - - if (appId.empty()) - { - LOGERR("Invalid appId"); - } - else - { - /* Re-attempting to create Storage Manager Object if the previous attempt failed (i.e., object is null) */ - if (nullptr == mStorageManagerObject) - { - if (Core::ERROR_NONE != createStorageManagerPluginObject()) - { - LOGERR("Re-attempt failed to create Storage Manager Object"); - } - } - - if (nullptr != mStorageManagerObject) - { - if (Core::ERROR_NONE == (status = mStorageManagerObject->GetStorage(appId, appStorageInfo.userId, appStorageInfo.groupId, - appStorageInfo.path, appStorageInfo.size, appStorageInfo.used))) - { - LOGINFO("Received Storage Manager info for %s [path %s, userId %d, groupId %d, size %d, used %d]", - appId.c_str(), appStorageInfo.path.c_str(), appStorageInfo.userId, - appStorageInfo.groupId, appStorageInfo.size, appStorageInfo.used); - } - else - { - LOGERR("Failed to get Storage Manager info"); - } - } - } - - return status; - } - - bool RuntimeManagerImplementation::generate(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject, std::string& dobbySpec) - { - DobbySpecGenerator generator; - return generator.generate(config, runtimeConfigObject, dobbySpec); - } - - Exchange::IRuntimeManager::RuntimeState RuntimeManagerImplementation::getRuntimeState(const string& appInstanceId) - { - Exchange::IRuntimeManager::RuntimeState runtimeState = Exchange::IRuntimeManager::RUNTIME_STATE_UNKNOWN; - - Core::SafeSyncType lock(mRuntimeManagerImplLock); - - if (!appInstanceId.empty()) - { - if(mRuntimeAppInfo.find(appInstanceId) == mRuntimeAppInfo.end()) - { - LOGERR("Missing appInstanceId[%s] in RuntimeAppInfo", appInstanceId.c_str()); - } - else - { - runtimeState = mRuntimeAppInfo[appInstanceId].containerState; - } - } - else - { - LOGERR("appInstanceId param is missing"); - } - - return runtimeState; - } - - bool RuntimeManagerImplementation::isOCIPluginObjectValid(void) - { - return (mOciContainerObject != nullptr) || - (createOCIContainerPluginObject() == Core::ERROR_NONE); - } - - std::string RuntimeManagerImplementation::getContainerId(const string& appInstanceId) - { - string containerId = ""; - - if (!appInstanceId.empty()) - { - containerId = mRuntimeAppPortal + appInstanceId; - } - return containerId; - } - Core::hresult RuntimeManagerImplementation::Run(const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, IValueIterator* const& ports, IStringIterator* const& paths, IStringIterator* const& debugSettings, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject) - { - Core::hresult status = Core::ERROR_GENERAL; - RuntimeAppInfo runtimeAppInfo; - std::string xdgRuntimeDir = ""; - std::string waylandDisplay = ""; - std::string dobbySpec; - AppStorageInfo appStorageInfo; - int32_t descriptor = -1; - std::string errorReason = ""; - bool success = false; - std::string westerosSocket = ""; - ApplicationConfiguration config; - config.mAppId = appId; - config.mAppInstanceId = appInstanceId; - bool displayResult = false; - bool notifyParamCheckFailure = false; - std::string errorCode = ""; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of run for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - JsonObject eventData; - eventData["containerId"] = appInstanceId; - eventData["state"] = static_cast(RUNTIME_STATE_STARTING); - eventData["eventName"] = "onContainerStateChanged"; - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_STATECHANGED, eventData); - - mRuntimeManagerImplLock.Lock(); - - uid_t uid = mUserIdManager->getUserId(appId); - gid_t gid = mUserIdManager->getAppsGid(); - - std::ifstream inFile("/tmp/specchange"); - if (inFile.good()) - { - uid = 30490; - } - config.mUserId = uid; - config.mGroupId = gid; - - if (ports) - { - std::uint32_t port; - while (ports->Next(port)) - { - config.mPorts.push_back(port); - } - } - - // if (paths) - // { - // std::string path; - // while (paths->Next(path)) - // { - // config.mPaths.push_back(path); - // } - // } - - if (debugSettings) - { - std::string debugSetting; - while (debugSettings->Next(debugSetting)) - { - config.mDebugSettings.push_back(debugSetting); - } - } - - LOGINFO("ApplicationConfiguration populated for InstanceId: %s", appInstanceId.c_str()); - - if (runtimeConfigObject.envVariables.empty()) - { - LOGERR("envVariables is empty inside Run()"); - } - - if (!appId.empty()) - { - appStorageInfo.userId = userId; - appStorageInfo.groupId = groupId; - if (Core::ERROR_NONE == getAppStorageInfo(appId, appStorageInfo)) - { - config.mAppStorageInfo.path = std::move(appStorageInfo.path); - config.mAppStorageInfo.userId = userId; - config.mAppStorageInfo.groupId = groupId; - config.mAppStorageInfo.size = std::move(appStorageInfo.size); - config.mAppStorageInfo.used = std::move(appStorageInfo.used); - } - } - - /* Creating Display */ - if(nullptr != mWindowManagerConnector) - { - - mWindowManagerConnector->getDisplayInfo(appInstanceId, xdgRuntimeDir, waylandDisplay); - displayResult = mWindowManagerConnector->createDisplay(appInstanceId, waylandDisplay, uid, gid); - if(false == displayResult) - { - LOGERR("Failed to create display"); - status = Core::ERROR_GENERAL; - } - else - { - LOGINFO("Display [%s] created successfully", waylandDisplay.c_str()); - } - - } - else - { - LOGERR("WindowManagerConnector is null"); - status = Core::ERROR_GENERAL; - } - - if (!xdgRuntimeDir.empty() && !waylandDisplay.empty()) - { - westerosSocket = xdgRuntimeDir + "/" + waylandDisplay; - config.mWesterosSocketPath = westerosSocket; - } - - bool legacyContainer = true; -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED - mRialtoConnector->initialize(); - if (mRialtoConnector->createAppSession(appId,westerosSocket, appId)) - { - if (!mRialtoConnector->waitForStateChange(appId,RialtoServerStates::ACTIVE, RIALTO_TIMEOUT_MILLIS)) - { - LOGWARN(" Rialto app session not ready. "); - status = Core::ERROR_GENERAL; - } - } - else - { - LOGWARN(" Rialto app session not ready. "); - status = Core::ERROR_GENERAL; - } - legacyContainer = false; -#endif // RIALTO_IN_DAC_FEATURE_ENABLED - LOGINFO("legacyContainer: %s", legacyContainer ? "true" : "false"); - if (xdgRuntimeDir.empty() || waylandDisplay.empty() || !displayResult) - { - LOGERR("Missing required environment variables: XDG_RUNTIME_DIR=%s, WAYLAND_DISPLAY=%s createDisplay %s", - xdgRuntimeDir.empty() ? "NOT FOUND" : xdgRuntimeDir.c_str(), - waylandDisplay.empty() ? "NOT FOUND" : waylandDisplay.c_str(), - displayResult ? "Success" : "Failed"); - status = Core::ERROR_GENERAL; - errorCode = "ERROR_CREATE_DISPLAY"; - notifyParamCheckFailure = true; - } - /* Generate dobbySpec */ - else if (legacyContainer && false == RuntimeManagerImplementation::generate(config, runtimeConfigObject, dobbySpec)) - { - LOGERR("Failed to generate dobbySpec"); - status = Core::ERROR_GENERAL; - errorCode = "ERROR_DOBBY_SPEC"; - notifyParamCheckFailure = true; - } - else - { - /* Generated dobbySpec */ - LOGINFO("Generated dobbySpec: %s", dobbySpec.c_str()); - - LOGINFO("Environment Variables: XDG_RUNTIME_DIR=%s, WAYLAND_DISPLAY=%s", - xdgRuntimeDir.c_str(), waylandDisplay.c_str()); - std::string command = ""; - std::string appPath = runtimeConfigObject.unpackedPath; - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - if (!containerId.empty()) - { - if(legacyContainer) - status = mOciContainerObject->StartContainerFromDobbySpec(containerId, dobbySpec, command, westerosSocket, descriptor, success, errorReason); - else - status = mOciContainerObject->StartContainer(containerId, appPath, command, westerosSocket, descriptor, success, errorReason); - - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to Run Container %s",errorReason.c_str()); - } - else - { - LOGINFO("Update Info for %s",appInstanceId.c_str()); - if (!appId.empty()) - { - runtimeAppInfo.appId = std::move(appId); - } - runtimeAppInfo.appInstanceId = std::move(appInstanceId); - runtimeAppInfo.descriptor = std::move(descriptor); - runtimeAppInfo.containerState = Exchange::IRuntimeManager::RUNTIME_STATE_STARTING; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Store request time and type in runtime app info map */ - runtimeAppInfo.requestTime = requestTime; - runtimeAppInfo.requestType = REQUEST_TYPE_LAUNCH; -#endif - /* Insert/update runtime app info */ - mRuntimeAppInfo[runtimeAppInfo.appInstanceId] = std::move(runtimeAppInfo); - } - } - else - { - LOGERR("appInstanceId is not found "); - errorCode = "ERROR_INVALID_PARAM"; - notifyParamCheckFailure = true; - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Run."); - } - } - mRuntimeManagerImplLock.Unlock(); - if(notifyParamCheckFailure) - { - notifyParameterCheckFailure(appInstanceId, errorCode); - } - return status; - } - - Core::hresult RuntimeManagerImplementation::Hibernate(const string& appInstanceId) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string options = ""; - std::string errorReason = ""; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - std::string appId = ""; -#endif - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of hibernate for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - if (!containerId.empty()) - { - status = mOciContainerObject->HibernateContainer(containerId, options, success, errorReason); - if ((success == false)) - { - LOGERR("Failed to HibernateContainer %s",errorReason.c_str()); - status = Core::ERROR_GENERAL; //todo return proper error code in OCIContainerPlugin - } - else - { - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - mRuntimeAppInfo[appInstanceId].containerState = Exchange::IRuntimeManager::RUNTIME_STATE_HIBERNATING; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appId = mRuntimeAppInfo[appInstanceId].appId; -#endif - } - } - } - else - { - LOGERR("appInstanceId is not found or mOciContainerObject is not ready"); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Hibernate."); - } - mRuntimeManagerImplLock.Unlock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordTelemetryData(TELEMETRY_MARKER_HIBERNATE_TIME, appId, requestTime); -#endif - - return status; - } - - Core::hresult RuntimeManagerImplementation::Wake(const string& appInstanceId, const RuntimeState runtimeState) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - std::string appId = ""; -#endif - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of wake for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - if (!containerId.empty()) - { - RuntimeState currentRuntimeState = getRuntimeState(appInstanceId); - if (Exchange::IRuntimeManager::RUNTIME_STATE_HIBERNATING == currentRuntimeState || - Exchange::IRuntimeManager::RUNTIME_STATE_HIBERNATED == currentRuntimeState) - { - status = mOciContainerObject->WakeupContainer(containerId, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to WakeupContainer %s",errorReason.c_str()); - } - else - { - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - mRuntimeAppInfo[appInstanceId].containerState = Exchange::IRuntimeManager::RUNTIME_STATE_WAKING; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - appId = mRuntimeAppInfo[appInstanceId].appId; -#endif - } - } - } - else - { - LOGERR("Container is Not in Hibernating/Hiberanted state"); - } - } - else - { - LOGERR("appInstanceId is not found "); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Wake."); - } - mRuntimeManagerImplLock.Unlock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordTelemetryData(TELEMETRY_MARKER_WAKE_TIME, appId, requestTime); -#endif - - return status; - } - - Core::hresult RuntimeManagerImplementation::Suspend(const string& appInstanceId) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - std::string appId = ""; -#endif - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of suspend for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - status = mOciContainerObject->PauseContainer(containerId, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to PauseContainer %s",errorReason.c_str()); - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - else - { - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - appId = mRuntimeAppInfo[appInstanceId].appId; - } - } -#endif - } - else - { - LOGERR("appInstanceId is not found "); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Suspend."); - } - mRuntimeManagerImplLock.Unlock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordTelemetryData(TELEMETRY_MARKER_SUSPEND_TIME, appId, requestTime); -#endif - - return status; - } - - Core::hresult RuntimeManagerImplementation::Resume(const string& appInstanceId) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - std::string appId = ""; -#endif - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of resume for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - status = mOciContainerObject->ResumeContainer(containerId, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to ResumeContainer %s",errorReason.c_str()); - } -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - else - { - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - appId = mRuntimeAppInfo[appInstanceId].appId; - } - } -#endif - } - else - { - LOGERR("appInstanceId is empty "); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Resume."); - } - mRuntimeManagerImplLock.Unlock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - recordTelemetryData(TELEMETRY_MARKER_RESUME_TIME, appId, requestTime); -#endif - - return status; - } - - Core::hresult RuntimeManagerImplementation::Terminate(const string& appInstanceId) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of terminate for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - auto it = mRuntimeAppInfo.find(appInstanceId); - if (it != mRuntimeAppInfo.end()) - { - it->second.requestTime = requestTime; - it->second.requestType = REQUEST_TYPE_TERMINATE; - } - else - { - LOGERR("Terminate called for unknown appInstanceId: %s, skipping telemetry update", appInstanceId.c_str()); - } -#endif - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - status = mOciContainerObject->StopContainer(containerId, false, success, errorReason); - if (errorReason.compare("Container not found") == 0) - { - LOGINFO("Container is not running, no need to StopContainer"); - status = Core::ERROR_NONE; - mUserIdManager->clearUserId(appInstanceId); - } - else if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("StopContainer failed to terminate %s",errorReason.c_str()); - } - else - { - mUserIdManager->clearUserId(appInstanceId); - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - mRuntimeAppInfo[appInstanceId].containerState = Exchange::IRuntimeManager::RUNTIME_STATE_TERMINATING; - } - } - } - else - { - LOGERR("appInstanceId is not found"); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Terminate."); - } -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED - LOGINFO("Rialto session deactivate on terminate."); - mRialtoConnector->deactivateSession(mRuntimeAppInfo[appInstanceId].appId); - if (!mRialtoConnector->waitForStateChange(mRuntimeAppInfo[appInstanceId].appId,RialtoServerStates::NOT_RUNNING, RIALTO_TIMEOUT_MILLIS)) - { - LOGERR("Rialto session state change failed when changing to not running."); - status = Core::ERROR_GENERAL; - } -#endif // RIALTO_IN_DAC_FEATURE_ENABLED - mRuntimeManagerImplLock.Unlock(); - return status; - } - - Core::hresult RuntimeManagerImplementation::Kill(const string& appInstanceId) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; - bool success = false; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the start of terminate for telemetry */ - time_t requestTime = getCurrentTimestamp(); -#endif - - mRuntimeManagerImplLock.Lock(); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - auto it = mRuntimeAppInfo.find(appInstanceId); - if (it != mRuntimeAppInfo.end()) - { - it->second.requestTime = requestTime; - it->second.requestType = REQUEST_TYPE_KILL; - } - else - { - LOGERR("Kill called for unknown appInstanceId: %s, skipping telemetry update", appInstanceId.c_str()); - } -#endif - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - status = mOciContainerObject->StopContainer(containerId, true, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to StopContainer for Kill %s",errorReason.c_str()); - } - else - { - mUserIdManager->clearUserId(appInstanceId); - if (mRuntimeAppInfo.find(appInstanceId) != mRuntimeAppInfo.end()) - { - mRuntimeAppInfo[appInstanceId].containerState = Exchange::IRuntimeManager::RUNTIME_STATE_TERMINATING; - } - } - } - else - { - LOGERR("appInstanceId is not found"); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting Kill."); - } -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED - LOGINFO("Rialto Session deactivate on kill.."); - mRialtoConnector->deactivateSession(mRuntimeAppInfo[appInstanceId].appId); - if (!mRialtoConnector->waitForStateChange(mRuntimeAppInfo[appInstanceId].appId,RialtoServerStates::NOT_RUNNING, RIALTO_TIMEOUT_MILLIS)) - { - LOGERR("Rialto session state change failed when changing to not running "); - status = Core::ERROR_GENERAL; - } -#endif // RIALTO_IN_DAC_FEATURE_ENABLED - mRuntimeManagerImplLock.Unlock(); - return status; - } - - Core::hresult RuntimeManagerImplementation::GetInfo(const string& appInstanceId, string& info) - { - Core::hresult status = Core::ERROR_GENERAL; - LOGINFO("Entered GetInfo Implementation"); - std::string errorReason = ""; - bool success = false; - - mRuntimeManagerImplLock.Lock(); - - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - status = mOciContainerObject->GetContainerInfo(containerId, info, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to GetContainerInfo %s",errorReason.c_str()); - } - else - { - LOGINFO("GetContainerInfo is success"); - } - } - else - { - LOGERR("appInstanceId is not found or mOciContainerObject is not ready"); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting GetInfo."); - } - mRuntimeManagerImplLock.Unlock(); - return status; - } - - Core::hresult RuntimeManagerImplementation::Annotate(const string& appInstanceId, const string& key, const string& value) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason = ""; - bool success = false; - - mRuntimeManagerImplLock.Lock(); - - if(isOCIPluginObjectValid()) - { - string containerId = getContainerId(appInstanceId); - - if (!containerId.empty()) - { - if (key.empty()) - { - LOGERR("Annotate: key is empty"); - } - else - { - status = mOciContainerObject->Annotate(containerId, key, value, success, errorReason); - if ((success == false) || (status != Core::ERROR_NONE)) - { - LOGERR("Failed to Annotate property key: %s value: %s errorReason %s",key.c_str(), value.c_str(), errorReason.c_str()); - } - } - } - else - { - LOGERR("appInstanceId is empty "); - } - } - else - { - LOGERR("OCI Plugin object is not valid. Aborting GetInfo."); - } - mRuntimeManagerImplLock.Unlock(); - return status; - } - - Core::hresult RuntimeManagerImplementation::Mount() - { - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("Mount Implementation - Stub!"); - - return status; - } - - Core::hresult RuntimeManagerImplementation::Unmount() - { - Core::hresult status = Core::ERROR_NONE; - - LOGINFO("Unmount Implementation - Stub!"); - - return status; - } - - void RuntimeManagerImplementation::onOCIContainerStartedEvent(std::string name, JsonObject& data) - { - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_CONTAINERSTARTED, data); - } - - void RuntimeManagerImplementation::onOCIContainerStoppedEvent(std::string name, JsonObject& data) - { - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_CONTAINERSTOPPED, data); - } - - void RuntimeManagerImplementation::onOCIContainerFailureEvent(std::string name, JsonObject& data) - { - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_CONTAINERFAILED, data); - } - - void RuntimeManagerImplementation::onOCIContainerStateChangedEvent(std::string name, JsonObject& data) - { - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_STATECHANGED, data); - } - - void RuntimeManagerImplementation::notifyParameterCheckFailure(const string& appInstanceId, const string& errorCode) - { - JsonObject data; - data["containerId"] = getContainerId(appInstanceId); - data["errorCode"] = errorCode; - data["eventName"] = "onParameterCheckFailed"; - dispatchEvent(RuntimeManagerImplementation::RuntimeEventType::RUNTIME_MANAGER_EVENT_CONTAINERFAILED, data); - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - - time_t RuntimeManagerImplementation::getCurrentTimestamp() - { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((time_t)ts.tv_sec * 1000) + ((time_t)ts.tv_nsec / 1000000)); - } - - RuntimeManagerImplementation::TelemetryMarker RuntimeManagerImplementation::getTelemetryMarker(const std::string& marker) - { - if (marker == TELEMETRY_MARKER_LAUNCH_TIME) - return TELEMETRY_MARKER_LAUNCH; - else if (marker == TELEMETRY_MARKER_CLOSE_TIME) - return TELEMETRY_MARKER_CLOSE; - else if (marker == TELEMETRY_MARKER_RESUME_TIME) - return TELEMETRY_MARKER_RESUME; - else if (marker == TELEMETRY_MARKER_SUSPEND_TIME) - return TELEMETRY_MARKER_SUSPEND; - else if (marker == TELEMETRY_MARKER_HIBERNATE_TIME) - return TELEMETRY_MARKER_HIBERNATE; - else if (marker == TELEMETRY_MARKER_WAKE_TIME) - return TELEMETRY_MARKER_WAKE; - else - return TELEMETRY_MARKER_UNKNOWN; - } - - void RuntimeManagerImplementation::recordTelemetryData(const std::string& marker, const std::string& appId, uint64_t requestTime) - { - /* End time for telemetry */ - time_t currentTime = getCurrentTimestamp(); - LOGERR("End time for %s: %lu", marker.c_str(), currentTime); - - JsonObject jsonParam; - std::string telemetryMetrics = ""; - - int duration = static_cast(currentTime - requestTime); - TelemetryMarker telemetryMarker = getTelemetryMarker(marker); - - /* Determine the telemetry JSON key */ - switch(telemetryMarker) - { - case TELEMETRY_MARKER_RESUME: - jsonParam["runtimeManagerResumeTime"] = duration; - break; - case TELEMETRY_MARKER_SUSPEND: - jsonParam["runtimeManagerSuspendTime"] = duration; - break; - case TELEMETRY_MARKER_HIBERNATE: - jsonParam["runtimeManagerHibernateTime"] = duration; - break; - case TELEMETRY_MARKER_WAKE: - jsonParam["runtimeManagerWakeTime"] = duration; - break; - case TELEMETRY_MARKER_LAUNCH: - jsonParam["runtimeManagerRunTime"] = duration; - break; - case TELEMETRY_MARKER_CLOSE: - jsonParam["runtimeManagerTerminateTime"] = duration; - break; - default: - LOGERR("Unknown telemetry marker: %s", marker.c_str()); - return; - } - jsonParam["appId"] = appId; - jsonParam.ToString(telemetryMetrics); - - if(nullptr != mTelemetryMetricsObject) - { - LOGINFO("Record appId %s marker %s start time %d",appId.c_str(), marker.c_str(), duration); - mTelemetryMetricsObject->Record(appId, telemetryMetrics, marker); - } - } -#endif - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/RuntimeManagerImplementation.h b/RuntimeManager/RuntimeManagerImplementation.h deleted file mode 100755 index e1269dc..0000000 --- a/RuntimeManager/RuntimeManagerImplementation.h +++ /dev/null @@ -1,255 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include -#include -#include -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include -#endif -#include -#include "ApplicationConfiguration.h" -#include "WindowManagerConnector.h" -#include "IEventHandler.h" -#include "DobbyEventListener.h" -#include "UserIdManager.h" - -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED -#include "RialtoConnector.h" -#define RIALTO_TIMEOUT_MILLIS 5000 -#endif -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#define TELEMETRY_MARKER_CLOSE_TIME "AppCloseTime_split" -#define TELEMETRY_MARKER_SUSPEND_TIME "SuspendTime_split" -#define TELEMETRY_MARKER_RESUME_TIME "ResumeTime_split" -#define TELEMETRY_MARKER_HIBERNATE_TIME "HibernateTime_split" -#define TELEMETRY_MARKER_WAKE_TIME "WakeTime_split" -#endif - -namespace WPEFramework -{ - namespace Plugin - { - class RuntimeManagerImplementation : public Exchange::IRuntimeManager, public Exchange::IConfiguration, public IEventHandler - { - private: - class Configuration : public Core::JSON::Container { - public: - Configuration() - : Core::JSON::Container() - , runtimeAppPortal() - { - Add(_T("runtimeAppPortal"), &runtimeAppPortal); - } - ~Configuration() = default; - - Configuration(Configuration&&) = delete; - Configuration(const Configuration&) = delete; - Configuration& operator=(Configuration&&) = delete; - Configuration& operator=(const Configuration&) = delete; - - public: - Core::JSON::String runtimeAppPortal; - }; - - public: - enum RuntimeEventType - { - RUNTIME_MANAGER_EVENT_UNKNOWN = 0, - RUNTIME_MANAGER_EVENT_STATECHANGED, - RUNTIME_MANAGER_EVENT_CONTAINERSTARTED, - RUNTIME_MANAGER_EVENT_CONTAINERSTOPPED, - RUNTIME_MANAGER_EVENT_CONTAINERFAILED - }; - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - enum RequestType { - REQUEST_TYPE_NONE, - REQUEST_TYPE_LAUNCH, - REQUEST_TYPE_SUSPEND, - REQUEST_TYPE_RESUME, - REQUEST_TYPE_HIBERNATE, - REQUEST_TYPE_WAKE, - REQUEST_TYPE_TERMINATE, - REQUEST_TYPE_KILL - }; - - enum TelemetryMarker { - TELEMETRY_MARKER_UNKNOWN = 0, - TELEMETRY_MARKER_LAUNCH, - TELEMETRY_MARKER_CLOSE, - TELEMETRY_MARKER_RESUME, - TELEMETRY_MARKER_SUSPEND, - TELEMETRY_MARKER_HIBERNATE, - TELEMETRY_MARKER_WAKE - }; -#endif - - typedef struct _RuntimeAppInfo - { - std::string appId; - std::string appInstanceId; - uint32_t descriptor; - Exchange::IRuntimeManager::RuntimeState containerState; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - time_t requestTime = 0; - RuntimeManagerImplementation::RequestType requestType = RuntimeManagerImplementation::REQUEST_TYPE_NONE; -#endif - } RuntimeAppInfo; - - class EXTERNAL Job : public Core::IDispatch - { - protected: - Job(RuntimeManagerImplementation *mRuntimeManagerImpl, RuntimeEventType event, JsonValue ¶ms) - : mRuntimeManagerImplementation(mRuntimeManagerImpl) - , _event(event) - , _params(params) - { - if (mRuntimeManagerImplementation != nullptr) - { - mRuntimeManagerImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() - { - if (mRuntimeManagerImplementation != nullptr) - { - mRuntimeManagerImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(RuntimeManagerImplementation *mRuntimeManagerImpl, RuntimeEventType event, JsonValue params) - { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(mRuntimeManagerImpl, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(mRuntimeManagerImpl, event, params))); -#endif - } - - virtual void Dispatch() - { - mRuntimeManagerImplementation->Dispatch(_event, _params); - } - - private: - RuntimeManagerImplementation *mRuntimeManagerImplementation; - const RuntimeEventType _event; - const JsonValue _params; - }; - - RuntimeManagerImplementation (); - ~RuntimeManagerImplementation () override; - - RuntimeManagerImplementation (const RuntimeManagerImplementation &) = delete; - RuntimeManagerImplementation & operator=(const RuntimeManagerImplementation &) = delete; - - static RuntimeManagerImplementation* getInstance(); - - BEGIN_INTERFACE_MAP(RuntimeManagerImplementation) - INTERFACE_ENTRY(Exchange::IRuntimeManager) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - /* IRuntimeManager methods */ - virtual Core::hresult Register(Exchange::IRuntimeManager::INotification *notification) override; - virtual Core::hresult Unregister(Exchange::IRuntimeManager::INotification *notification) override; - - virtual Core::hresult Run(const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, IValueIterator* const& ports, IStringIterator* const& paths, IStringIterator* const& debugSettings, const WPEFramework::Exchange::RuntimeConfig& runtimeConfigObject) override; - virtual Core::hresult Hibernate(const string& appInstanceId) override; - virtual Core::hresult Wake(const string& appInstanceId, const RuntimeState runtimeState) override; - virtual Core::hresult Suspend(const string& appInstanceId) override; - virtual Core::hresult Resume(const string& appInstanceId) override; - virtual Core::hresult Terminate(const string& appInstanceId) override; - virtual Core::hresult Kill(const string& appInstanceId) override; - virtual Core::hresult GetInfo(const string& appInstanceId, string& info) override; - virtual Core::hresult Annotate(const string& appInstanceId, const string& key, const string& value) override; - virtual Core::hresult Mount() override; - virtual Core::hresult Unmount() override; - - // IConfiguration methods - uint32_t Configure(PluginHost::IShell* service) override; - - // IEventHandler methods - virtual void onOCIContainerStartedEvent(std::string name, JsonObject& data) override; - virtual void onOCIContainerStoppedEvent(std::string name, JsonObject& data) override; - virtual void onOCIContainerFailureEvent(std::string name, JsonObject& data) override; - virtual void onOCIContainerStateChangedEvent(std::string name, JsonObject& data) override; - - private: /* private methods */ - Core::hresult createOCIContainerPluginObject(); - void releaseOCIContainerPluginObject(); - Core::hresult createStorageManagerPluginObject(); - void releaseStorageManagerPluginObject(); - static bool generate(const ApplicationConfiguration& config, const WPEFramework::Exchange::RuntimeConfig& runtimeConfig, std::string& dobbySpec); - std::string getContainerId(const string& appInstanceId); - bool isOCIPluginObjectValid(void); - Exchange::IRuntimeManager::RuntimeState getRuntimeState(const string& appInstanceId); - Core::hresult getAppStorageInfo(const string& appId, AppStorageInfo& appStorageInfo); - - private: /* members */ - mutable Core::CriticalSection mRuntimeManagerImplLock; - PluginHost::IShell* mCurrentservice; - Exchange::IOCIContainer* mOciContainerObject; - std::list mRuntimeManagerNotification; - std::map mRuntimeAppInfo; - Exchange::IStorageManager *mStorageManagerObject; - WindowManagerConnector* mWindowManagerConnector; - DobbyEventListener *mDobbyEventListener; - UserIdManager* mUserIdManager; - std::string mRuntimeAppPortal; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - Exchange::ITelemetryMetrics* mTelemetryMetricsObject; -#endif -#ifdef RIALTO_IN_DAC_FEATURE_ENABLED - std::shared_ptr mRialtoConnector; -#endif // RIALTO_IN_DAC_FEATURE_ENABLED - - private: /* internal methods */ - void dispatchEvent(RuntimeEventType, const JsonValue ¶ms); - void Dispatch(RuntimeEventType event, const JsonValue params); - void notifyParameterCheckFailure(const string& appInstanceId, const string& errorCode); - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - void recordTelemetryData(const std::string& marker, const std::string& appId, uint64_t requestTime); - TelemetryMarker getTelemetryMarker(const std::string& marker); - time_t getCurrentTimestamp(); -#endif - - friend class Job; - - public/*members*/: - static RuntimeManagerImplementation* _instance; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/RuntimeManager/UserIdManager.cpp b/RuntimeManager/UserIdManager.cpp deleted file mode 100755 index 16027d6..0000000 --- a/RuntimeManager/UserIdManager.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "UserIdManager.h" - -namespace WPEFramework { -namespace Plugin { - -UserIdManager::UserIdManager() - :mValidUidRange(getAppsUidRange()) -{ - unsigned int count = 0u; - for (uid_t uid = mValidUidRange.first; uid <= mValidUidRange.second; uid++) - { - if (count++ > 1000u) - break; - - mUserIdAvailablePool.push_back(uid); - } - - if (mUserIdAvailablePool.empty()) - { - printf("Depleted user id pool, none available for new apps"); - } - -} - -uid_t UserIdManager::getUserId(const std::string& appId) -{ - std::lock_guard lock(mLock); - - auto found = mUserIdMap.find(appId); - if (found != mUserIdMap.end()) - { - return found->second; - } - - if (mUserIdAvailablePool.size() < 5u) - { - printf("Pool of available uids has been depleted, refusing to give" - " app '%s' a uid", appId.c_str()); - return 0; - } - - uid_t uid = mUserIdAvailablePool.front(); - mUserIdAvailablePool.pop_front(); - - mUserIdMap[appId] = uid; - return uid; -} - -void UserIdManager::clearUserId(const std::string & appId) -{ - std::lock_guard lock(mLock); - - std::map::iterator found = mUserIdMap.find(appId); - if (found != mUserIdMap.end()) - { - mUserIdAvailablePool.push_back(found->second); - mUserIdMap.erase(found); - } -} - -std::pair UserIdManager::getAppsUidRange() -{ - return std::make_pair(30001, 31000); -} - -gid_t UserIdManager::getAppsGid() -{ - return 30000; -} -} // namespace Plugin -} // namespace WPEFramework diff --git a/RuntimeManager/UserIdManager.h b/RuntimeManager/UserIdManager.h deleted file mode 100755 index 1481733..0000000 --- a/RuntimeManager/UserIdManager.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef USERIDMANAGER_H -#define USERIDMANAGER_H - -#include -#include -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class UserIdManager - { - public: - UserIdManager(); - uid_t getUserId(const std::string& appId); - void clearUserId(const std::string & appId); - gid_t getAppsGid(); - - private: - std::pair getAppsUidRange(); - mutable std::mutex mLock; - std::map mUserIdMap; - std::list mUserIdAvailablePool; - const std::pair mValidUidRange; - }; - -} // namespace Plugin -} // namespace WPEFramework - -#endif // !defined(USERIDMANAGER_H) diff --git a/RuntimeManager/WindowManagerConnector.cpp b/RuntimeManager/WindowManagerConnector.cpp deleted file mode 100644 index 5de9331..0000000 --- a/RuntimeManager/WindowManagerConnector.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "WindowManagerConnector.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { - -WindowManagerConnector::WindowManagerConnector() -: mWindowManager(nullptr), mWindowManagerNotification(*this) -{ - LOGINFO("Create WindowManagerConnector Instance"); -} - -WindowManagerConnector::~WindowManagerConnector() -{ - LOGINFO("Delete WindowManagerConnector Instance"); -} - -bool WindowManagerConnector::initializePlugin(PluginHost::IShell* service) -{ - bool ret = false; - if (nullptr == service) - { - LOGWARN("service is null \n"); - } - else if (nullptr == (mWindowManager = service->QueryInterfaceByCallsign("org.rdk.RDKWindowManager"))) - { - LOGWARN("Failed to create WindowManager object\n"); - } - else - { - LOGINFO("Created WindowManager Object \n"); - mWindowManager->AddRef(); - ret = true; - mPluginInitialized = true; - Core::hresult registerResult = mWindowManager->Register(&mWindowManagerNotification); - if (Core::ERROR_NONE != registerResult) - { - LOGINFO("Unable to register with windowmanager [%d] \n", registerResult); - } - } - return ret; -} - -void WindowManagerConnector::releasePlugin() -{ - if(mPluginInitialized == false) - { - LOGERR("WindowManagerConnector is not initialized \n"); - return; - } - Core::hresult releaseResult = mWindowManager->Unregister(&mWindowManagerNotification); - if (Core::ERROR_NONE != releaseResult) - { - LOGINFO("Unable to unregister from windowmanager [%d] \n", releaseResult); - } - uint32_t result = mWindowManager->Release(); - mPluginInitialized = false; - LOGINFO("Window manager releases [%d]\n", result); - mWindowManager = nullptr; -} - -bool WindowManagerConnector::createDisplay(const string& appInstanceId , const string& displayName , const uint32_t& userId, const uint32_t& groupId) -{ - if(mPluginInitialized == false) - { - LOGERR("WindowManagerConnector is not initialized \n"); - return false; - } - JsonObject displayParams; - displayParams["client"] = appInstanceId; - displayParams["displayName"] = displayName; - - displayParams["ownerId"] = userId; - displayParams["groupId"] = groupId; - string displayParamsString; - displayParams.ToString(displayParamsString); - - LOGINFO("Creating display [%s] for application [%s] with params [%s] \n", displayName.c_str(), appInstanceId.c_str(), displayParamsString.c_str());//remove - - Core::hresult result = mWindowManager->CreateDisplay(displayParamsString); - if (Core::ERROR_NONE != result) - { - LOGERR("Failed to create display for application [%s] error [%d] \n",appInstanceId.c_str(), result); - return false; - } - - return true; -} - -bool WindowManagerConnector::isPluginInitialized() -{ - return mPluginInitialized; -} - -void WindowManagerConnector::getDisplayInfo(const string& appInstanceId , string& xdgDirectory , string& waylandDisplayName) -{ - std::pair name; - - int xdgRuntimeDirFd = -1; - const char *xdgRuntimeDir = getenv("XDG_RUNTIME_DIR"); - if (xdgRuntimeDir) - { - xdgRuntimeDirFd = open(xdgRuntimeDir, O_CLOEXEC | O_DIRECTORY); - if (xdgRuntimeDirFd < 0) - { - printf("failed to open XDG_RUNTIME_DIR '%s' %d\n", xdgRuntimeDir, errno); - fflush(stdout); - } - else - { - xdgDirectory = xdgRuntimeDir; - } - } - // if failed to open the dir then open the default /tmp - if (xdgRuntimeDirFd < 0) - { - xdgRuntimeDirFd = open("/tmp", O_CLOEXEC | O_DIRECTORY); - if (xdgRuntimeDirFd < 0) - { - printf("failed to open XDG_RUNTIME_DIR /tmp %d\n", errno); - fflush(stdout); - } - xdgDirectory = "/tmp"; - } - std::ifstream f("/tmp/specchange1"); - if (f.good()) - { - waylandDisplayName = "testdisplay"; - f.close(); - } - else - { - // generate name as wst-appInstanceId and sanity check - string displayName = "wst-" + appInstanceId; - if (faccessat(xdgRuntimeDirFd, displayName.c_str(), F_OK, 0) != 0) //todo required for wst-appinstanceid? - { - waylandDisplayName = std::move(displayName); - } - else - { - LOGERR("Display name already exists, using default display name\n"); - waylandDisplayName = "testdisplay"; - } - } - if (close(xdgRuntimeDirFd) < 0) - { - printf("failed to close XDG_RUNTIME_DIR \n"); - fflush(stdout); - } - - LOGINFO("GetDisplayInfo::Returning display name [%s] for display [%s] \n", waylandDisplayName.c_str(), xdgDirectory.c_str()); -} - -void WindowManagerConnector::WindowManagerNotification::OnUserInactivity(const double minutes) -{ -} - -} // namespace Plugin -} // namespace WPEFramework diff --git a/RuntimeManager/WindowManagerConnector.h b/RuntimeManager/WindowManagerConnector.h deleted file mode 100644 index 3721109..0000000 --- a/RuntimeManager/WindowManagerConnector.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - class WindowManagerConnector - { - class WindowManagerNotification : public Exchange::IRDKWindowManager::INotification - { - private: - WindowManagerNotification(const WindowManagerNotification&) = delete; - WindowManagerNotification& operator=(const WindowManagerNotification&) = delete; - - public: - explicit WindowManagerNotification(WindowManagerConnector& parent) - : _parent(parent) - { - } - - ~WindowManagerNotification() override = default; - BEGIN_INTERFACE_MAP(WindowManagerNotification) - INTERFACE_ENTRY(Exchange::IRDKWindowManager::INotification) - END_INTERFACE_MAP - - virtual void OnUserInactivity(const double minutes) override; - - private: - WindowManagerConnector& _parent; - }; - public: - WindowManagerConnector(); - ~WindowManagerConnector(); - - // We do not allow this plugin to be copied !! - WindowManagerConnector(const WindowManagerConnector&) = delete; - WindowManagerConnector& operator=(const WindowManagerConnector&) = delete; - - public: - bool initializePlugin(PluginHost::IShell* service); //, IEventHandler* eventHandler - void releasePlugin(); - bool createDisplay(const string& appInstanceId , const string& displayName, const uint32_t& userId, const uint32_t& groupId); - bool isPluginInitialized(); - void getDisplayInfo(const string& appInstanceId , string& xdgRuntimeDir , string& waylandDisplayName);\ - private: - Exchange::IRDKWindowManager* mWindowManager; - Core::Sink mWindowManagerNotification; - bool mPluginInitialized = false; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/RustAdapter/CHANGELOG.md b/RustAdapter/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/RustAdapter/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/RustAdapter/CMakeLists.txt b/RustAdapter/CMakeLists.txt deleted file mode 100644 index 7cb4f70..0000000 --- a/RustAdapter/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME RustAdapter) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -if (USE_THUNDER_R4) - set(CMAKE_CXX_FLAGS "-DJSON_RPC_CONTEXT ${CMAKE_CXX_FLAGS}") -endif() - -add_library(${MODULE_NAME} SHARED - RustAdapter.cpp - LocalPlugin.cpp - RemotePlugin.cpp - SocketServer.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_include_directories(${MODULE_NAME} PRIVATE ../helpers) - -target_link_libraries(${MODULE_NAME} PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) diff --git a/RustAdapter/LocalPlugin.cpp b/RustAdapter/LocalPlugin.cpp deleted file mode 100644 index d406686..0000000 --- a/RustAdapter/LocalPlugin.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "RustAdapter.h" -#include "LocalPlugin.h" -#include "Logger.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { -namespace Rust { - struct RequestContext { - uint32_t channel_id; - const char *auth_token; - }; - - struct PluginContext { - uint32_t id; - std::function send_to; - }; - - -} } } - -namespace { - std::atomic_int ctx_next_id = {1}; - std::vector< WPEFramework::Plugin::Rust::PluginContext * > ctx_array; - - // this function is passed into Rust as a pointer - extern "C" void wpe_send_to(uint32_t channel_id, const char *json, uint32_t ctx_id) - { - for (WPEFramework::Plugin::Rust::PluginContext *ctx : ctx_array) { - if (ctx->id == ctx_id) { - ctx->send_to(channel_id, json); - break; - } - } - } - - std::vector get_library_search_paths() - { - std::vector paths = {}; - - char *ld_paths = getenv("LD_LIBRARY_PATH"); - if (ld_paths) { - - char *ld_pathBackup = strdup(ld_paths); - ld_paths = ld_pathBackup; - char *p = nullptr; - char *saveptr = nullptr; - while ((p = strtok_r(ld_paths, ":", &saveptr)) != nullptr) { - paths.push_back(string(p)); - ld_paths = nullptr; - } - if (ld_pathBackup) { - free(ld_pathBackup); - } - } - return paths; - } - - inline string to_string(const WPEFramework::Core::JSONRPC::Message &m) - { - string s; - m.ToString(s); - return s; - } - - bool file_exists(const string &path) - { - struct stat statbuf = {}; - return stat(path.c_str(), &statbuf) != -1; - } - - void *find_rust_plugin(const string &fname) - { - void *lib = nullptr; - if (file_exists(fname)) { - LOGDBG("Loading library from:%s\n", fname.c_str()); - lib = dlopen(fname.c_str(), RTLD_LAZY); - if (!lib) - LOGERR("Failed to load %s. %s", fname.c_str(), dlerror()); - } - else { - //MARKR is this needed because dlopen docs says it searches LD_LIBRARY_PATH paths by default - for (const string &path : get_library_search_paths()) { - string full_path = path + "/" + fname; - if (file_exists(full_path)) { - LOGDBG("Loading library from:%s\n", full_path.c_str()); - lib = dlopen(full_path.c_str(), RTLD_LAZY); - if (!lib) - LOGERR("Failed to load %s. %s", full_path.c_str(), dlerror()); - break; - } - } - } - return lib; - } -} - -WPEFramework::Plugin::Rust::LocalPlugin::LocalPlugin(const RustAdapter::Config &config) - : m_rust_plugin_create(nullptr) - , m_rust_plugin_destroy(nullptr) - , m_rust_plugin_init(nullptr) - , m_rust_plugin_invoke(nullptr) - , m_rust_plugin_on_client_connect(nullptr) - , m_rust_plugin_on_client_disconnect(nullptr) - , m_refcount(1) - , m_rust_plugin(nullptr) - , m_rust_plugin_lib(nullptr) - , m_service(nullptr) - , m_config(config) -{ -} - -const string -WPEFramework::Plugin::Rust::LocalPlugin::Initialize(PluginHost::IShell *shell) -{ - m_service = shell; - m_auth_token = RustAdapter::GetAuthToken(shell, shell->Callsign()); - - std::string lib_name = RustAdapter::GetLibraryPathOrName(m_config.LibName.Value(), shell->Callsign()); - - m_rust_plugin_lib = find_rust_plugin(lib_name); - if (!m_rust_plugin_lib) { - std::stringstream buff; - buff << "cannot find "; - buff << lib_name; - return buff.str(); - } - - // - // TODO: we should compile libWPEFrameworkRust.so into libWPEFrameworkRust.a - // and link it with libthunder_rs.so. In that case, we probably won't have to - // dynamically bind all the functions - // - m_rust_plugin_create = (RustPlugin_Create) dlsym(m_rust_plugin_lib, "wpe_rust_plugin_create"); - m_rust_plugin_init = (RustPlugin_Init) dlsym(m_rust_plugin_lib, "wpe_rust_plugin_init"); - m_rust_plugin_destroy = (RustPlugin_Destroy) dlsym(m_rust_plugin_lib, "wpe_rust_plugin_destroy"); - m_rust_plugin_invoke = (RustPlugin_Invoke) dlsym(m_rust_plugin_lib, "wpe_rust_plugin_invoke"); - m_rust_plugin_on_client_connect = (RustPlugin_OnClientConnect) - dlsym(m_rust_plugin_lib, "wpe_rust_plugin_on_client_connect"); - m_rust_plugin_on_client_disconnect = (RustPlugin_OnClientDisconnect) - dlsym(m_rust_plugin_lib, "wpe_rust_plugin_on_client_disconnect"); - - Rust::PluginContext *plugin_ctx = new Rust::PluginContext(); - plugin_ctx->send_to = std::bind(&LocalPlugin::SendTo, this, - std::placeholders::_1, std::placeholders::_2); - plugin_ctx->id = ctx_next_id++; - ctx_array.push_back(plugin_ctx); - - void *metadata = dlsym(m_rust_plugin_lib, "thunder_service_metadata"); - - // create and initialize the rust plugin - m_rust_plugin = m_rust_plugin_create(shell->ClassName().c_str(), &wpe_send_to, plugin_ctx->id, - m_auth_token.c_str(), - metadata); - - // XXX: The call to "init" doesn't seem necessary - m_rust_plugin_init(m_rust_plugin, nullptr); - - return {}; -} - -void -WPEFramework::Plugin::Rust::LocalPlugin::Deinitialize(PluginHost::IShell *shell) -{ - if (m_rust_plugin) { - m_rust_plugin_destroy(m_rust_plugin); - m_rust_plugin = nullptr; - } -} - -void -WPEFramework::Plugin::Rust::LocalPlugin::SendTo(uint32_t channel_id, const char *json) -{ - auto res = Core::ProxyType>::Create(); - res->FromString(json); - m_service->Submit(channel_id, Core::ProxyType(res)); -} - -#if JSON_RPC_CONTEXT - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) -WPEFramework::Core::hresult - WPEFramework::Plugin::Rust::LocalPlugin::Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) -{ - Rust::RequestContext req_ctx; - req_ctx.channel_id = channelId; - req_ctx.auth_token = token.c_str(); - m_rust_plugin_invoke(m_rust_plugin, response.c_str(), req_ctx); - // indicates to Thunder that this request is being processed asynchronously - return {}; -} -#else -WPEFramework::Core::ProxyType -WPEFramework::Plugin::Rust::LocalPlugin::Invoke( - const WPEFramework::Core::JSONRPC::Context &ctx, - const WPEFramework::Core::JSONRPC::Message &req) -{ - Rust::RequestContext req_ctx; - req_ctx.channel_id = ctx.ChannelId(); - req_ctx.auth_token = ctx.Token().c_str(); - - m_rust_plugin_invoke(m_rust_plugin, to_string(req).c_str(), req_ctx); - - // indicates to Thunder that this request is being processed asynchronously - return {}; -} -#endif -#else -WPEFramework::Core::ProxyType - WPEFramework::Plugin::Rust::LocalPlugin::Invoke( - const string& token, const uint32_t channelId, const Core::JSONRPC::Message& req) -{ - Rust::RequestContext req_ctx; - req_ctx.channel_id = channelId; - req_ctx.auth_token = token.c_str(); - - m_rust_plugin_invoke(m_rust_plugin, to_string(req).c_str(), req_ctx); - - // indicates to Thunder that this request is being processed asynchronously - return {}; -} -#endif - -#if ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 4)) -WPEFramework::Core::hresult WPEFramework::Plugin::Rust::LocalPlugin::Revoke(ICallback* callback) -{ - return {}; -} -WPEFramework::Core::hresult WPEFramework::Plugin::Rust::LocalPlugin::Validate(const string& token, const string& method, const string& paramaters) const -{ - return {}; -} -#endif - -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) -void -WPEFramework::Plugin::Rust::LocalPlugin::Activate( - WPEFramework::PluginHost::IShell *shell) -{ -} - -void -WPEFramework::Plugin::Rust::LocalPlugin::Deactivate() -{ -} -#endif - -bool -WPEFramework::Plugin::Rust::LocalPlugin::Attach(PluginHost::Channel &channel) -{ - m_rust_plugin_on_client_connect(m_rust_plugin, channel.Id()); - return true; -} - -void -WPEFramework::Plugin::Rust::LocalPlugin::Detach(PluginHost::Channel &channel) -{ - m_rust_plugin_on_client_disconnect(m_rust_plugin, channel.Id()); -} - -WPEFramework::Core::ProxyType -WPEFramework::Plugin::Rust::LocalPlugin::Inbound(const string &identifier) -{ - return WPEFramework::Core::ProxyType( - WPEFramework::PluginHost::IFactories::Instance().JSONRPC()); -} - -WPEFramework::Core::ProxyType -WPEFramework::Plugin::Rust::LocalPlugin::Inbound(const uint32_t id, - const Core::ProxyType &element) -{ - Core::ProxyType req(element); - - Rust::RequestContext req_ctx; - req_ctx.channel_id = id; - req_ctx.auth_token = ""; - - m_rust_plugin_invoke(m_rust_plugin, to_string(*req).c_str(), req_ctx); - - // I don't know what this return value is used for, but Invoke() returns {} to - // indicate that the request is being processed asynchronously - return {}; -} - -void -WPEFramework::Plugin::Rust::LocalPlugin::AddRef() const -{ - // TODO -} - -uint32_t -WPEFramework::Plugin::Rust::LocalPlugin::Release() const -{ - // TODO - return 0; -} - -string -WPEFramework::Plugin::Rust::LocalPlugin::Information() const -{ - return { }; -} - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 2)) -void WPEFramework::Plugin::Rust::LocalPlugin::Close(const uint32_t channelId) /* override */ -{ - return; -} -#endif /* THUNDER_VERSION */ diff --git a/RustAdapter/LocalPlugin.h b/RustAdapter/LocalPlugin.h deleted file mode 100644 index 24dc911..0000000 --- a/RustAdapter/LocalPlugin.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -namespace WPEFramework { -namespace Plugin { -namespace Rust { - -class LocalPlugin : public Rust::IPlugin -{ -public: - - /** - * - */ - LocalPlugin(const RustAdapter::Config &config); - - /** - * - */ - ~LocalPlugin() override = default; - - LocalPlugin(const LocalPlugin &) = delete; - LocalPlugin& operator = (const LocalPlugin &) = delete; - - /** - * IPlugin::Initialize - */ - const string Initialize(PluginHost::IShell *shell) override; - - /** - * IPlugin::Deinitialize - */ - void Deinitialize(PluginHost::IShell *shell) override; - - /** - * IPlugin Information - */ - string Information() const override; - - /** - * IDispatcher -> IUknown -> IReferenceCounted::AddRef - */ - void AddRef() const override; - - /** - * IDispatcher -> IUnknown -> IReferenceCounted::AddRef - */ - uint32_t Release() const override; - - BEGIN_INTERFACE_MAP(RustAdapter) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IPluginExtended) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_ENTRY(PluginHost::IWebSocket) - END_INTERFACE_MAP - - /** - * IDispatcher::Activate - */ -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - void Activate(PluginHost::IShell *shell) override; - /** - * - */ - void Deactivate() override; -#endif - /** - * - */ - bool Attach(PluginHost::Channel &channel) override; - void Detach(PluginHost::Channel &channel) override; - - /** - * IDispatcher::Close - */ -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 2)) - void Close(const uint32_t channelId) override; -#endif /* THUNDER_VERSION */ - /** - * WPEFramework::PluginHost::IDispatcher::Invoke - */ -#if JSON_RPC_CONTEXT - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - Core::hresult Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response ) override; -#else - Core::ProxyType Invoke( - const Core::JSONRPC::Context& context, - const Core::JSONRPC::Message& message) override; -#endif - -#else - Core::ProxyType Invoke( - const string& token, const uint32_t channelId, const Core::JSONRPC::Message& req) override; -#endif - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - Core::hresult Revoke(ICallback* callback) override; - Core::hresult Validate(const string& token, const string& method, const string& paramaters /* @restrict:(4M-1) */) const override; -#endif - /** - * - */ - Core::ProxyType Inbound(const string &identifier) override; - Core::ProxyType Inbound(const uint32_t id, - const Core::ProxyType &element) override; - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) -public: - WPEFramework::PluginHost::ILocalDispatcher* Local() override { - return nullptr; // Replace nullptr with your actual implementation. - } -#endif /* THUNDER_VERSION */ - -private: - using RustPlugin_SendTo = void (*)(uint32_t, const char *, uint32_t ctx_id); - using RustPlugin_Create = Rust::Plugin *(*)(const char *name, RustPlugin_SendTo send_to, - uint32_t plugin_ctx_id, const char *jwt, void *); - using RustPlugin_Destroy = void (*)(Rust::Plugin *p); - using RustPlugin_Init = void (*)(Rust::Plugin *p, const char *json); - using RustPlugin_Invoke = void (*)(Rust::Plugin *p, const char *json_req, - Rust::RequestContext req_ctx); - using RustPlugin_OnClientConnect = void (*)(Rust::Plugin *p, uint32_t channel_id); - using RustPlugin_OnClientDisconnect = void (*)(Rust::Plugin *p, uint32_t channel_id); - - - RustPlugin_Create m_rust_plugin_create; - RustPlugin_Destroy m_rust_plugin_destroy; - RustPlugin_Init m_rust_plugin_init; - RustPlugin_Invoke m_rust_plugin_invoke; - RustPlugin_OnClientConnect m_rust_plugin_on_client_connect; - RustPlugin_OnClientDisconnect m_rust_plugin_on_client_disconnect; - - mutable std::atomic m_refcount; - - // this is mutable because AddRef() and Release() are const - mutable Rust::Plugin *m_rust_plugin; - - // this needs to stay around until plugin is deleted, otherwise - // it'll call dlclose() and we'll lose dynamically bound symbols - void *m_rust_plugin_lib; - - // we keep a pointer to this to allow rust code to callback into - // the Adapter and send messages/events asynchronously - // XXX: We could also capture a reference to the channel during - // attach/detach, but that may require API changes to Thunder/internal - PluginHost::IShell *m_service; - RustAdapter::Config m_config; - std::string m_auth_token; - -private: - void SendTo(uint32_t channel_id, const char *json); -}; -} } } diff --git a/RustAdapter/Logger.h b/RustAdapter/Logger.h deleted file mode 100644 index d8e16c0..0000000 --- a/RustAdapter/Logger.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include - -#ifndef LOGINFO -#define LOGINFO(fmt, ...) do { fprintf(stderr, "[%d] INFO [%s:%d] %s: " fmt "\n", (int)syscall(SYS_gettid), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); fflush(stderr); } while (0) -#define LOGDBG(fmt, ...) do { fprintf(stderr, "[%d] DEBUG [%s:%d] %s: " fmt "\n", (int)syscall(SYS_gettid), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); fflush(stderr); } while (0) -#define LOGWARN(fmt, ...) do { fprintf(stderr, "[%d] WARN [%s:%d] %s: " fmt "\n", (int)syscall(SYS_gettid),__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); fflush(stderr); } while (0) -#define LOGERR(fmt, ...) do { fprintf(stderr, "[%d] ERROR [%s:%d] %s: " fmt "\n", (int)syscall(SYS_gettid), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); fflush(stderr); } while (0) -#endif diff --git a/RustAdapter/Module.cpp b/RustAdapter/Module.cpp deleted file mode 100644 index 560b367..0000000 --- a/RustAdapter/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/RustAdapter/Module.h b/RustAdapter/Module.h deleted file mode 100644 index 35ae5ae..0000000 --- a/RustAdapter/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_RustAdapter -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/RustAdapter/RemotePlugin.cpp b/RustAdapter/RemotePlugin.cpp deleted file mode 100644 index 18bd0fc..0000000 --- a/RustAdapter/RemotePlugin.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "RustAdapter.h" -#include "RemotePlugin.h" -#include "SocketServer.h" -#include "Logger.h" -#include - -namespace WPEFramework { -namespace Plugin { -namespace Rust { - -RemotePlugin::RemotePlugin(const RustAdapter::Config &conf) - : m_remotePid(0) - , m_config(conf) -{ -} - -const string -RemotePlugin::Initialize(PluginHost::IShell *shell) -{ - m_service = shell; - m_auth_token = RustAdapter::GetAuthToken(shell, shell->Callsign()); - - string address = m_config.Address.Value(); - printf("ADDR=%s\n", address.c_str()); - if (address.empty()) - address = "127.0.0.1"; - - if (m_stream.Open(address, - m_config.Port.Value(), - std::bind(&RemotePlugin::onRead, this, std::placeholders::_1)) < 0) - { - return string("RustAdapter RemotePlugin couldn't open socket stream"); - } - - if (m_stream.RunThread() < 0) - { - return string("RustAdapter RemotePlugin failed to run stream thread"); - } - - if (m_config.AutoExec) - { - std::string lib_name = RustAdapter::GetLibraryPathOrName(m_config.LibName.Value(), shell->Callsign()); - if ((m_remotePid = LaunchRemoteProcess(lib_name, m_stream.GetAddress(), m_stream.GetPort())) < 0) - { - return string("RustAdapter RemotePlugin failed spawn remote process"); - } - } - - return {}; -} - -void -RemotePlugin::Deinitialize(PluginHost::IShell *shell) -{ - - LOGDBG("Deinitialize: send exit message to any connected client"); - m_stream.SendExit(); - - if (m_remotePid > 0) - { - int status; - LOGDBG("Deinitialize: waiting on remote %d to close", m_remotePid); - waitpid(m_remotePid, &status, 0); - LOGDBG("Deinitialize:remote closed status=%d", status); - } - - m_stream.Close(); - LOGDBG("RemotePlugin::Deinitialize exit"); -} - -void -RemotePlugin::SendTo(uint32_t channel_id, const char *json) -{ - auto res = Core::ProxyType>::Create(); - res->FromString(json); - m_service->Submit(channel_id, Core::ProxyType(res)); -} -#if JSON_RPC_CONTEXT -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) -WPEFramework::Core::hresult RemotePlugin::Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response) -{ - m_stream.SendInvoke(channelId, token, response); - return {}; -} -#else -WPEFramework::Core::ProxyType -RemotePlugin::Invoke( - const WPEFramework::Core::JSONRPC::Context &ctx, - const WPEFramework::Core::JSONRPC::Message &req) -{ - string json; - req.ToString(json); - m_stream.SendInvoke(ctx.ChannelId(), ctx.Token(), json); - return {}; -} -#endif -#else -WPEFramework::Core::ProxyType -RemotePlugin::Invoke( - const string& token, const uint32_t channelId, const Core::JSONRPC::Message& req) -{ - string json; - req.ToString(json); - m_stream.SendInvoke(channelId, token, json); - return {}; -} -#endif - -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) -void -RemotePlugin::Activate( - WPEFramework::PluginHost::IShell *shell) -{ -} -void -RemotePlugin::Deactivate() -{ -} -#endif - -bool -RemotePlugin::Attach(PluginHost::Channel &channel) -{ - LOGDBG("RemotePlugin::Attach %d\n", channel.Id()); - m_stream.SendAttach(channel.Id(), true); - return true; -} - -void -RemotePlugin::Detach(PluginHost::Channel &channel) -{ - LOGDBG("RemotePlugin::Detach %d\n", channel.Id()); - m_stream.SendAttach(channel.Id(), false); -} - -WPEFramework::Core::ProxyType -RemotePlugin::Inbound(const string &identifier) -{ - return WPEFramework::Core::ProxyType( - WPEFramework::PluginHost::IFactories::Instance().JSONRPC()); -} - -WPEFramework::Core::ProxyType -RemotePlugin::Inbound(const uint32_t id, - const Core::ProxyType &element) -{ - LOGDBG("NO IMPL %s\n", __PRETTY_FUNCTION__); - return {}; -} - -void -RemotePlugin::AddRef() const -{ - // TODO -} - -uint32_t -RemotePlugin::Release() const -{ - // TODO - return 0; -} - -string -RemotePlugin::Information() const -{ - return { }; -} - -#if (THUNDER_VERSION >= 4) -#if (THUNDER_VERSION_MINOR == 2) -void RemotePlugin::Close(const uint32_t channelId) /* override */ -{ - return; -} -#endif -#if (THUNDER_VERSION_MINOR == 4) -WPEFramework::Core::hresult RemotePlugin::Revoke(ICallback* callback) -{ - return {}; -} -WPEFramework::Core::hresult RemotePlugin::Validate(const string& token, const string& method, const string& paramaters) const -{ - return {}; -} -#endif -#endif - -void RemotePlugin::onRead(const Response& rsp) -{ - LOGDBG("RemotePlugin::onRead response: channel_id=%u, json=\"%s\"", rsp.channel_id, rsp.json.c_str()); - SendTo(rsp.channel_id, rsp.json.c_str()); -} - -int RemotePlugin::LaunchRemoteProcess(const string& rust_shared_lib, const string& host_ip, int port) -{ - string appName = "WPEHost"; - - int pid = fork(); - - if (pid == 0) - { - std::stringstream ssPort; - ssPort << port; - - char const* argv[] = { - appName.c_str(), - rust_shared_lib.c_str(), - host_ip.c_str(), - ssPort.str().c_str(), - nullptr - }; - - - if (!m_auth_token.empty()) - setenv("THUNDER_SECURITY_TOKEN", m_auth_token.c_str(), 1); - - if (execvp(appName.c_str(), (char**)argv) < 0) - { - LOGERR("Failed launch remote app %s: %s", appName.c_str(), strerror(errno)); - _exit(errno); - } - } - else if (pid < 0) - { - LOGERR("Failed to fork process"); - } - else - { - //TODO: verify child is running - } - - return pid; -} - -} } } diff --git a/RustAdapter/RemotePlugin.h b/RustAdapter/RemotePlugin.h deleted file mode 100644 index c0beed9..0000000 --- a/RustAdapter/RemotePlugin.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "SocketServer.h" - -namespace WPEFramework { -namespace Plugin { -namespace Rust { - -class RemotePlugin : public Rust::IPlugin -{ -public: - - /** - * - */ - RemotePlugin(const RustAdapter::Config &conf); - - /** - * - */ - ~RemotePlugin() override = default; - - RemotePlugin(const RemotePlugin &) = delete; - RemotePlugin& operator = (const RemotePlugin &) = delete; - - /** - * IPlugin::Initialize - */ - const string Initialize(PluginHost::IShell *shell) override; - - /** - * IPlugin::Deinitialize - */ - void Deinitialize(PluginHost::IShell *shell) override; - - /** - * IPlugin Information - */ - string Information() const override; - - /** - * IDispatcher -> IUknown -> IReferenceCounted::AddRef - */ - void AddRef() const override; - - /** - * IDispatcher -> IUnknown -> IReferenceCounted::AddRef - */ - uint32_t Release() const override; - - BEGIN_INTERFACE_MAP(RustAdapter) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IPluginExtended) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_ENTRY(PluginHost::IWebSocket) - END_INTERFACE_MAP - - /** - * IDispatcher::Activate - */ -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - void Activate(PluginHost::IShell *shell) override; - /** - * - */ - void Deactivate() override; -#endif - /** - * - */ - bool Attach(PluginHost::Channel &channel) override; - void Detach(PluginHost::Channel &channel) override; - /** - * IDispatcher::Close - */ -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 2)) - void Close(const uint32_t channelId) override; -#endif - - /** - * IDispatcher::Close - */ -#if ((THUNDER_VERSION >= 4 && THUNDER_VERSION_MINOR == 4)) - Core::hresult Revoke(ICallback* callback) override; - Core::hresult Validate(const string& token, const string& method, const string& paramaters /* @restrict:(4M-1) */) const override; -#endif /* THUNDER_VERSION */ - /** - * WPEFramework::PluginHost::IDispatcher::Invoke - */ -#if JSON_RPC_CONTEXT - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - Core::hresult Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response ) override; -#else - Core::ProxyType Invoke( - const Core::JSONRPC::Context& context, - const Core::JSONRPC::Message& message) override; -#endif -#else - Core::ProxyType Invoke( - const string& token, const uint32_t channelId, const Core::JSONRPC::Message& req) override; -#endif - /** - * - */ - Core::ProxyType Inbound(const string &identifier) override; - Core::ProxyType Inbound(const uint32_t id, - const Core::ProxyType &element) override; - - void onRead(const Response& rsp); -#if ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 4)) -public: - WPEFramework::PluginHost::ILocalDispatcher* Local() override { - return nullptr; // Replace nullptr with your actual implementation. - } -#endif - -private: - int LaunchRemoteProcess(const string& rust_shared_lib, const string& host_ip, int port); - void SendTo(uint32_t channel_id, const char *json); - - // we keep a pointer to this to allow rust code to callback into - // the Adapter and send messages/events asynchronously - // XXX: We could also capture a reference to the channel during - // attach/detach, but that may require API changes to Thunder/internal - PluginHost::IShell *m_service; - int m_remotePid; - SocketServer m_stream; - RustAdapter::Config m_config; - std::string m_auth_token; -}; - -} } } diff --git a/RustAdapter/RustAdapter.cpp b/RustAdapter/RustAdapter.cpp deleted file mode 100644 index 32c313a..0000000 --- a/RustAdapter/RustAdapter.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "RustAdapter.h" -#include "LocalPlugin.h" -#include "RemotePlugin.h" -#include "Logger.h" -#include -#include "UtilsSearchRDKProfile.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 1 - -namespace WPEFramework { -namespace { - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - SERVICE_REGISTRATION(RustAdapter, 1, 0); -} } - -WPEFramework::Plugin::RustAdapter::RustAdapter() - : m_refcount(1) -{ -} - -const string -WPEFramework::Plugin::RustAdapter::Initialize(PluginHost::IShell *shell) -{ - /* The RustAdapter plugin should always run in-process - We run the rust plugin itself either in-process or out-of-process - base the config setting */ - - profileType = searchRdkProfile(); - - if (profileType == STB || profileType == NOT_FOUND) - { - LOGINFO("Invalid profile type for TV \n"); - return (std::string("Not supported")); - } - - RustAdapter::Config conf; - conf.FromString(shell->ConfigLine()); - - LOGINFO("RustAdapter::Initialize Config=%s", shell->ConfigLine().c_str()); - - if (conf.OutOfProcess) - m_impl.reset(new WPEFramework::Plugin::Rust::RemotePlugin(conf)); - else - m_impl.reset(new WPEFramework::Plugin::Rust::LocalPlugin(conf)); - - return m_impl->Initialize(shell); -} - -void -WPEFramework::Plugin::RustAdapter::Deinitialize(PluginHost::IShell *shell) -{ - - profileType = searchRdkProfile(); - - if (profileType == STB || profileType == NOT_FOUND) - { - LOGINFO("Invalid profile type for TV \n"); - return ; - } - - return m_impl->Deinitialize(shell); -} - -string -WPEFramework::Plugin::RustAdapter::Information() const -{ - return m_impl->Information(); -} - -void -WPEFramework::Plugin::RustAdapter::AddRef() const -{ - m_refcount++; -} - -uint32_t -WPEFramework::Plugin::RustAdapter::Release() const -{ - uint32_t n = m_refcount.fetch_sub(1); - if (n == 1) { - delete this; - return Core::ERROR_DESTRUCTION_SUCCEEDED; - } - - return Core::ERROR_NONE; -} - -#if JSON_RPC_CONTEXT -#if ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 4)) -WPEFramework::Core::hresult -WPEFramework::Plugin::RustAdapter::Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response ) -{ - return m_impl->Invoke(callback, channelId,id, token, method, parameters, response); -} -#else -WPEFramework::Core::ProxyType -WPEFramework::Plugin::RustAdapter::Invoke( - const WPEFramework::Core::JSONRPC::Context &ctx, - const WPEFramework::Core::JSONRPC::Message &req) -{ - return m_impl->Invoke(ctx, req); -} -#endif -#else -WPEFramework::Core::ProxyType - WPEFramework::Plugin::RustAdapter::Invoke( - const string& token, const uint32_t channelId, const WPEFramework::Core::JSONRPC::Message& req) -{ - return m_impl->Invoke(token, channelId, req); -} -#endif - -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) -void -WPEFramework::Plugin::RustAdapter::Activate( - WPEFramework::PluginHost::IShell *shell) -{ - m_impl->Activate(shell); -} -void -WPEFramework::Plugin::RustAdapter::Deactivate() -{ - m_impl->Deactivate(); -} -#endif -bool -WPEFramework::Plugin::RustAdapter::Attach(PluginHost::Channel &channel) -{ - return m_impl->Attach(channel); -} -void -WPEFramework::Plugin::RustAdapter::Detach(PluginHost::Channel &channel) -{ - m_impl->Detach(channel); -} - -#if ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2)) -void -WPEFramework::Plugin::RustAdapter::Close(const uint32_t channelId) -{ - m_impl->Close(channelId); -} -#endif /* THUNDER_VERSION */ - -#if ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 4)) -WPEFramework::Core::hresult WPEFramework::Plugin::RustAdapter::Revoke(ICallback* callback) -{ - return {}; -} -WPEFramework::Core::hresult WPEFramework::Plugin::RustAdapter::Validate(const string& token, const string& method, const string& paramaters) const -{ - return {}; -} -#endif - -WPEFramework::Core::ProxyType -WPEFramework::Plugin::RustAdapter::Inbound(const string &identifier) -{ - return m_impl->Inbound(identifier); -} - -WPEFramework::Core::ProxyType -WPEFramework::Plugin::RustAdapter::Inbound(const uint32_t id, - const Core::ProxyType &element) -{ - return m_impl->Inbound(id, element); -} - -std::string -WPEFramework::Plugin::RustAdapter::GetLibraryPathOrName( - const std::string &lib_name, - const std::string &callsign) -{ - std::stringstream shared_library_name; - if (!lib_name.empty()) - shared_library_name << lib_name; - else { - shared_library_name << "lib"; - for (char c : callsign) - shared_library_name << static_cast(std::tolower(c)); - shared_library_name << ".so"; - } - return shared_library_name.str(); -} - -std::string -WPEFramework::Plugin::RustAdapter::GetAuthToken(WPEFramework::PluginHost::IShell* service, const std::string &callsign) -{ - std::string auth_token; - - char buff[256]; - memset(buff, 0, sizeof(buff)); - - int n = snprintf(buff, sizeof(buff), "plugin://%s", callsign.c_str()); - buff[255] = '\0'; - - auto auth = service->QueryInterfaceByCallsign("SecurityAgent"); - if (auth != nullptr) { - string encoded; - if (auth->CreateToken(n, (const uint8_t*) buff, encoded) == WPEFramework::Core::ERROR_NONE) { - auth_token = encoded; - } - auth->Release(); - } - - return auth_token; -} diff --git a/RustAdapter/RustAdapter.h b/RustAdapter/RustAdapter.h deleted file mode 100644 index 387b6c6..0000000 --- a/RustAdapter/RustAdapter.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include "Module.h" -#include "RustPlugin.h" - -namespace WPEFramework { -namespace Plugin { - -namespace Rust { - struct RequestContext; - struct PluginContext; - struct Plugin; -} - -class RustAdapter : public Rust::IPlugin -{ -public: - class Config : public Core::JSON::Container - { - private: - Config& operator=(const Config&); - public: - Config(const Config &rhs) - { - Add(_T("outofprocess"), &OutOfProcess); - Add(_T("address"), &Address); - Add(_T("port"), &Port); - Add(_T("autoexec"), &AutoExec); - Add(_T("libname"), &LibName); - OutOfProcess = rhs.OutOfProcess;; - Address = rhs.Address; - Port = rhs.Port; - AutoExec = rhs.AutoExec; - LibName = rhs.LibName; - } - - Config() : Core::JSON::Container(), OutOfProcess(false) - { - Add(_T("outofprocess"), &OutOfProcess); - Add(_T("address"), &Address); - Add(_T("port"), &Port); - Add(_T("autoexec"), &AutoExec); - Add(_T("libname"), &LibName); - } - ~Config() - { - } - public: - Core::JSON::Boolean OutOfProcess; - Core::JSON::String Address; - Core::JSON::DecUInt16 Port; - Core::JSON::Boolean AutoExec; - Core::JSON::String LibName; - }; - - /** - * - */ - RustAdapter(); - - /** - * - */ - ~RustAdapter() override = default; - - RustAdapter(const RustAdapter &) = delete; - RustAdapter& operator = (const RustAdapter &) = delete; - - /** - * IPlugin::Initialize - */ - const string Initialize(PluginHost::IShell *shell) override; - - /** - * IPlugin::Deinitialize - */ - void Deinitialize(PluginHost::IShell *shell) override; - - /** - * IPlugin Information - */ - string Information() const override; - - /** - * IDispatcher -> IUknown -> IReferenceCounted::AddRef - */ - void AddRef() const override; - - /** - * IDispatcher -> IUnknown -> IReferenceCounted::AddRef - */ - uint32_t Release() const override; - - /** - * IDispatcher::Activate - */ -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - void Activate(PluginHost::IShell *shell) override; - /** - * - */ - void Deactivate() override; -#endif - /** - * - */ - bool Attach(PluginHost::Channel &channel) override; - void Detach(PluginHost::Channel &channel) override; - /** - * IDispatcher::Close - */ -#if (THUNDER_VERSION >= 4) -#if (THUNDER_VERSION_MINOR == 2) - void Close(const uint32_t channelId) override; -#endif -#if (THUNDER_VERSION_MINOR == 4) - Core::hresult Revoke(ICallback* callback) override; - Core::hresult Validate(const string& token, const string& method, const string& paramaters /* @restrict:(4M-1) */) const override; -#endif -#endif - /** - * WPEFramework::PluginHost::IDispatcher::Invoke - */ -#if JSON_RPC_CONTEXT - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) - Core::hresult Invoke(ICallback* callback, const uint32_t channelId, const uint32_t id, const string& token, const string& method, const string& parameters, string& response ) override; -#else - Core::ProxyType Invoke( - const Core::JSONRPC::Context& context, - const Core::JSONRPC::Message& message) override; -#endif -#else - Core::ProxyType Invoke( - const string& token, const uint32_t channelId, const Core::JSONRPC::Message& message) override; -#endif - - /** - * - */ - Core::ProxyType Inbound(const string &identifier) override; - Core::ProxyType Inbound(const uint32_t id, - const Core::ProxyType &element) override; - - BEGIN_INTERFACE_MAP(RustAdapter) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IPluginExtended) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_ENTRY(PluginHost::IWebSocket) - END_INTERFACE_MAP - - static std::string GetLibraryPathOrName( - const std::string& libname, - const std::string& callsign); - - static std::string GetAuthToken(WPEFramework::PluginHost::IShell* service, const std::string &callsign); - -#if ((THUNDER_VERSION >= 4) && (THUNDER_VERSION_MINOR == 4)) -public: - WPEFramework::PluginHost::ILocalDispatcher* Local() override { - return nullptr; // Replace nullptr with your actual implementation. - } -#endif - -private: - std::unique_ptr m_impl; - - // needs to be mutable because Release() is const - mutable std::atomic m_refcount; -}; - -} } diff --git a/RustAdapter/RustPlugin.h b/RustAdapter/RustPlugin.h deleted file mode 100644 index c65fa85..0000000 --- a/RustAdapter/RustPlugin.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -namespace WPEFramework { -namespace Plugin { -namespace Rust { - struct IPlugin - : public WPEFramework::PluginHost::IPluginExtended - , public WPEFramework::PluginHost::IDispatcher - , public WPEFramework::PluginHost::IWebSocket - { - }; -} } } - diff --git a/RustAdapter/SocketServer.cpp b/RustAdapter/SocketServer.cpp deleted file mode 100644 index 2571229..0000000 --- a/RustAdapter/SocketServer.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "SocketServer.h" -#include "Logger.h" -#include -#include -#include -#include -#include -#include -#include - -enum CommandID -{ - ID_INVOKE = 1, - ID_ATTACH, - ID_EXIT -}; - -#pragma pack(push,1) -struct InvoketHeader -{ - uint32_t command_id; - uint32_t channel_id; - uint32_t token_len; - uint32_t json_len; -}; -#pragma pack(pop) - -#pragma pack(push,1) -struct AttachHeader -{ - uint32_t command_id; - uint32_t channel_id; - uint8_t attach; -}; -#pragma pack(pop) - -#pragma pack(push,1) -struct ResponseHeader -{ - uint32_t channel_id; - uint32_t json_len; -}; -#pragma pack(pop) - -Response::Response() -: channel_id(0), json() -{ -} - -Response::Response(uint32_t channel, const string& json_str) -: channel_id(channel), json(json_str) -{ -} - -#define CLIENT_DISCONNECT -2 - -SocketServer::SocketServer() -: m_serverSocket(0) -, m_clientSocket(0) -, m_running(false) -, m_address() -, m_port(0) -{ - -} - -SocketServer::~SocketServer() -{ - Close(); -} - -int SocketServer::Open(const string& address, int port, const function& reader) -{ - int sock; - struct sockaddr_in addr; - int rc; - - sock = socket(AF_INET, SOCK_STREAM, 0); - - if (sock < 0) - { - LOGERR("SocketServer::Open socket create failed: %s", strerror(errno)); - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - rc = inet_pton(AF_INET, address.c_str(), &addr.sin_addr); - - if (rc == 0) - { - LOGERR("SocketServer::Open inet_pton %s invalid ip format", address.c_str()); - close(sock); - return -1; - } - else if (rc < 0) - { - LOGERR("SocketServer::Open inet_pton %s failed: %s", address.c_str(), strerror(errno)); - close(sock); - return -1; - } - - LOGDBG("SocketServer::Open host_ip=%s sin_addr=%d (note that INADDR_ANY=%d)", address.c_str(), addr.sin_addr.s_addr, INADDR_ANY); - - int sock_flags = fcntl (sock, F_GETFD, 0); - if (sock_flags < 0) - { - LOGERR("SocketServer::Open fcntl get failed: %s", strerror(errno)); - close(sock); - return -1; - } - - sock_flags |= FD_CLOEXEC; - - if (fcntl(sock, F_SETFD, sock_flags) < 0) - { - LOGERR("SocketServer::Open fcntl set failed: %s", strerror(errno)); - close(sock); - return -1; - } - - if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) - { - LOGERR("SocketServer::Open bind failed: %s", strerror(errno)); - close(sock); - return -1; - } - - if (listen(sock, 4) < 0) - { - LOGERR("SocketServer::Open listen failed: %s", strerror(errno)); - close(sock); - return -1; - } - - m_reader = reader; - m_serverSocket = sock; - m_address = address; - - if (port) - { - m_port = port; - } - else - { - struct sockaddr_in cur; - socklen_t len = sizeof(cur); - if (getsockname(sock, (struct sockaddr *)&cur, &len) ==-0) - { - m_port = ntohs(cur.sin_port); - } - else - { - LOGERR("SocketServer::Open getsockname failed: %s", strerror(errno)); - } - } - - LOGDBG("SocketServer::Open successfully running on port %d", m_port); - return 0; -} - -int SocketServer::RunThread() -{ - if (pthread_create(&m_thread, nullptr, SocketServer::RunThreadFunc, this) != 0) - { - LOGERR("SocketServer::Open failed to create thread: %s",strerror(errno)); - return -1; - } - return 0; -} - -void* SocketServer::RunThreadFunc(void* arg) -{ - SocketServer* ss = (SocketServer*)arg; - ss->Run(); - return nullptr; -} - -int SocketServer::Run() -{ - if (m_serverSocket <= 0 || m_running) - return -1; - - m_running = true; - - while (m_running) - { - fd_set m_readSet; - fd_set m_exceptSet; - struct timeval tv; - int res; - - FD_ZERO(&m_readSet); - FD_ZERO(&m_exceptSet); - FD_SET(m_serverSocket, &m_readSet); - FD_SET(m_serverSocket, &m_exceptSet); - if (m_clientSocket) - { - FD_SET(m_clientSocket, &m_readSet); - FD_SET(m_clientSocket, &m_exceptSet); - } - - tv.tv_sec = 10; - tv.tv_usec = 0; - res = select((m_clientSocket > m_serverSocket ? m_clientSocket : m_serverSocket) + 1, - &m_readSet, NULL, &m_exceptSet, &tv); - - if (!m_running) - break; - - if (res < 0) - { - LOGERR("SocketServer::Open select failed: %s", strerror(errno)); - return -1; - } - - if (res == 0) - continue; - - if (FD_ISSET(m_serverSocket, &m_readSet)) - { - int clsock; - struct sockaddr_in claddr; - socklen_t cllen; - - cllen = sizeof(claddr); - memset(&claddr, 0, cllen); - - clsock = accept(m_serverSocket, (struct sockaddr*)&claddr, &cllen); - if (clsock < 0) - { - LOGERR("SocketServer::Open accept failed: %s", strerror(errno)); - } - else - { - LOGDBG("SocketServer::Open client connected"); - m_clientSocket = clsock; - } - } - - if (m_clientSocket) - { - if (FD_ISSET(m_clientSocket, &m_readSet)) - { - Response rsp; - int rc = ReadResponse(rsp); - if (rc >= 0) - { - m_reader(rsp); - } - else if (rc == CLIENT_DISCONNECT) - { - LOGDBG("SocketServer::Open client disconnected"); - close(m_clientSocket); - m_clientSocket = 0; - } - } - } - } - return 0; -} - -string SocketServer::GetAddress() const -{ - return m_address; -} - -int SocketServer::GetPort() const -{ - return m_port; -} - -void SocketServer::Close() -{ - if (m_serverSocket > 0) - { - if (m_running) - { - m_running = false; - } - close(m_clientSocket); - close(m_serverSocket); - m_serverSocket = 0; - } -} - -int SocketServer::ReadExact(uint8_t* p, int len) -{ - if (!p || len <= 0) - return -1; - - if (m_serverSocket <= 0 || m_clientSocket <= 0) - return -1; - - size_t remaining = (size_t)len; - - while (remaining > 0) - { - ssize_t num = read(m_clientSocket, p, remaining); - - if (num <= 0) - { - LOGERR("SocketServer::ReadExact failed: num=%zd", num); - - if (num == 0) - return CLIENT_DISCONNECT; - - return -1; - } - else - { - p += num; - remaining -= (size_t)num; - } - } - - if (remaining != 0) - { - LOGERR("SocketServer::ReadExact: failed: remaining=%zu", remaining); - return -1; - } - - return len; -} - -int SocketServer::SendInvoke(uint32_t channel_id, const string& token, const string& json) -{ - if (m_serverSocket <= 0 || m_clientSocket <= 0) - return -1; - - InvoketHeader header = { - htonl(ID_INVOKE), - htonl(channel_id), - htonl((uint32_t)token.length()), - htonl((uint32_t)json.length()) - }; - - int num = send(m_clientSocket, &header, sizeof(header), MSG_NOSIGNAL); - if (num != sizeof(header)) - { - LOGERR("SocketServer::SendInvoke failed to send header: num=%d", num); - return -1; - } - - if (token.length() > 0) - { - num = send(m_clientSocket, token.c_str(), token.length(), MSG_NOSIGNAL); - if (num != (ssize_t)token.length()) - { - LOGERR("SocketServer::SendInvoke failed to send token: num=%d", num); - return -1; - } - } - - if (json.length() > 0) - { - num = send(m_clientSocket, json.c_str(), json.length(), MSG_NOSIGNAL); - if (num != (ssize_t)json.length()) - { - LOGERR("SocketServer::SendInvoke failed to send json: num=%d", num); - return -1; - } - } - return 0; -} - -int SocketServer::SendAttach(uint32_t channel_id, bool attach) -{ - if (m_serverSocket <= 0 || m_clientSocket <= 0) - return -1; - - AttachHeader header = { - htonl(ID_ATTACH), - htonl(channel_id), - attach ? (uint8_t)1 : (uint8_t)0 - }; - - int num = send(m_clientSocket, &header, sizeof(header), MSG_NOSIGNAL); - if (num != sizeof(header)) - { - LOGERR("SocketServer::SendAttach failed to send header: num=%d", num); - return -1; - } - return 0; -} - -int SocketServer::SendExit() -{ - if (m_serverSocket <= 0 || m_clientSocket <= 0) - return -1; - - uint32_t command_id = htonl(ID_EXIT); - int num = send(m_clientSocket, &command_id, sizeof(command_id), MSG_NOSIGNAL); - if (num != sizeof(command_id)) - { - LOGERR("SocketServer::SendExit failed: num=%d", num); - return -1; - } - - /*break out of reader thread*/ - m_running = false; - - return 0; -} - -int SocketServer::ReadResponse(Response& rsp) -{ - if (m_serverSocket <= 0 || m_clientSocket <= 0) - return -1; - - ResponseHeader header; - int rc; - - if ((rc = ReadExact((uint8_t*)&header, (int)sizeof(ResponseHeader))) <= 0) - { - return rc; - } - - rsp.channel_id = ntohl(header.channel_id); - header.json_len = ntohl(header.json_len); - - LOGDBG("SocketServer::ReadResponse read header: channel_id=%u, json_len=%u", - rsp.channel_id, header.json_len); - - if (header.json_len > 0) - { - uint8_t* buffer; - buffer = (uint8_t*)malloc(header.json_len+1); - - if ((rc = ReadExact(buffer, (int)header.json_len)) <= 0) - { - free(buffer); - return rc; - } - - buffer[header.json_len] = 0; - rsp.json = (char*)buffer; - free(buffer); - } - return 0; -} \ No newline at end of file diff --git a/RustAdapter/SocketServer.h b/RustAdapter/SocketServer.h deleted file mode 100644 index 3f1afc2..0000000 --- a/RustAdapter/SocketServer.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include -#include - -using std::string; -using std::function; - -struct Response -{ - uint32_t channel_id; - string json; - - Response(); - Response(uint32_t channel, const string& json_str); -}; - -class SocketServer -{ -public: - SocketServer(); - ~SocketServer(); - int Open(const string& address, int port, const function& reader); - int RunThread(); - int Run(); - void Close(); - string GetAddress() const; - int GetPort() const; - int SendInvoke(uint32_t channel_id, const string& token, const string& json); - int SendAttach(uint32_t channel_id, bool attach); - int SendExit(); - int ReadResponse(Response& cmd); -private: - int ReadExact(uint8_t* p, int len); - static void* RunThreadFunc(void* arg); - - int m_serverSocket; - int m_clientSocket; - function m_reader; - bool m_running; - pthread_t m_thread; - string m_address; - int m_port; -}; diff --git a/SceneSet/CMakeLists.txt b/SceneSet/CMakeLists.txt deleted file mode 100644 index a20eea8..0000000 --- a/SceneSet/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2025 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME SceneSet) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(PLUGIN_SCENE_SET_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_SCENE_SET_AUTOSTART false CACHE STRING "Automatically start SceneSet plugin") -set(PLUGIN_SCENE_SET_EXTRA_LIBRARIES "") -set(PLUGIN_SCENE_SET_STARTUPORDER "" CACHE STRING "Automatically start SceneSet plugin") - -add_definitions(-DSCENE_SET_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DSCENE_SET_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DSCENE_SET_API_VERSION_NUMBER_PATCH=0) - - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - SceneSet.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(SceneSet.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - - -include_directories(../helpers) - - -set(SCENE_SET_INCLUDES $ENV{SCENE_SET_INCLUDES}) -separate_arguments(SCENE_SET_INCLUDES) -include_directories(BEFORE ${SCENE_SET_INCLUDES}) - -write_config(${PLUGIN_NAME}) diff --git a/SceneSet/Module.cpp b/SceneSet/Module.cpp deleted file mode 100644 index 42106eb..0000000 --- a/SceneSet/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/SceneSet/Module.h b/SceneSet/Module.h deleted file mode 100644 index da7ba5f..0000000 --- a/SceneSet/Module.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_SceneSet -#endif - -#include -#include -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/SceneSet/SceneSet.conf.in b/SceneSet/SceneSet.conf.in deleted file mode 100644 index 7077bb8..0000000 --- a/SceneSet/SceneSet.conf.in +++ /dev/null @@ -1,11 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.SceneSet" -autostart = "@PLUGIN_SCENE_SET_AUTOSTART@" -startuporder = "@PLUGIN_SCENE_SET_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_SCENE_SET_MODE@") -configuration.add("root", rootobject) -configuration.add("refAppName", "com.rdk.app.wpebrowser_2.38") diff --git a/SceneSet/SceneSet.config b/SceneSet/SceneSet.config deleted file mode 100644 index 23b351c..0000000 --- a/SceneSet/SceneSet.config +++ /dev/null @@ -1,15 +0,0 @@ -set (autostart ${PLUGIN_SCENE_SET_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.SceneSet") - -if(PLUGIN_SCENE_SET_STARTUPORDER) -set (startuporder ${PLUGIN_SCENE_SET_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_APP_MANAGER_MODE}) - end() -end() -ans(configuration) diff --git a/SceneSet/SceneSet.cpp b/SceneSet/SceneSet.cpp deleted file mode 100644 index 6643e44..0000000 --- a/SceneSet/SceneSet.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SceneSet.h" -#include - -#define SCENESET_DEFAULT_APPNAME "rdk-reference-app" - -namespace WPEFramework -{ - namespace Plugin - { - SceneSet::SceneSet() - : PluginHost::IPlugin(), mrefAppName(SCENESET_DEFAULT_APPNAME), mService(nullptr), mAppManager(nullptr), mNotification(*this) - { - } - - namespace - { - - static Metadata metadata( - // Version - SCENE_SET_API_VERSION_NUMBER_MAJOR, SCENE_SET_API_VERSION_NUMBER_MINOR, SCENE_SET_API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {}); - } - - const string SceneSet::Initialize(PluginHost::IShell *service) - { - string message=""; - string configStr; - ASSERT(service != nullptr); - ASSERT(mService == nullptr); - - LOGINFO(); - - mService = service; - mService->AddRef(); - - configStr = service->ConfigLine().c_str(); - LOGINFO("ConfigLine=%s", service->ConfigLine().c_str()); - SceneSet::Configuration config; - config.FromString(service->ConfigLine()); - mrefAppName = config.refAppName; - LOGINFO("refAppName=%s", mrefAppName.c_str()); - - if (!mrefAppName.empty()) { - mAppManager = mService->QueryInterfaceByCallsign("org.rdk.AppManager"); - } - - if (!mAppManager) { - SYSLOG(Logging::Startup, ("SceneSet: Failed to get AppManager interface")); - } - else { - mAppManager->AddRef(); - mAppManager->Register(&mNotification); - LOGINFO("AppManager notification registered"); - - // Start Reference App on plugin startup - StartReferenceApp(); - } - - return message; - - } - - void SceneSet::Deinitialize(PluginHost::IShell *service) - { - - LOGINFO(); - if (mService != nullptr) - { - ASSERT(mService == service); - if (mAppManager) - { - mAppManager->Unregister(&mNotification); - mAppManager->Release(); - mAppManager = nullptr; - } - mService->Release(); - mService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("SceneSet de-initialised")))); - } - } - - string SceneSet::Information() const - { - return (string()); - } - - void SceneSet::OnAppLifecycleStateChanged(const string &appId, const string &appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) - { - - LOGINFO("OnAppLifecycleStateChanged received appId: %s appInstanceId: %s newState: %u oldState: %u errorReason: %u\n", - appId.c_str(), - appInstanceId.c_str(), - newState, - oldState, - errorReason); - - } - - void SceneSet::StartReferenceApp() - { - // Launch Reference App using AppManager - LOGINFO(); - if (mAppManager) - { - LOGINFO(); - Core::hresult result = mAppManager->LaunchApp(mrefAppName, "", ""); - if (result == Core::ERROR_NONE) - { - SYSLOG(Logging::Startup, ("SceneSet: Reference App launched successfully")); - } - else - { - SYSLOG(Logging::Startup, ("SceneSet: Failed to launch Reference App")); - } - } - else - { - SYSLOG(Logging::Startup, ("SceneSet: AppManager instance not available")); - } - } - - void SceneSet::MonitorReferenceAppCrash() - { - LOGINFO(); - } - - void SceneSet::RestartReferenceApp() - { - // Listen for lifecycle state changes and restart Reference App if needed - SYSLOG(Logging::Startup, ("SceneSet: Reference App crashed, restarting...")); - } - - } // Plugin -} // WPEFramework diff --git a/SceneSet/SceneSet.h b/SceneSet/SceneSet.h deleted file mode 100644 index 5879ab5..0000000 --- a/SceneSet/SceneSet.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2025 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include "UtilsJsonRpc.h" -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - - class SceneSet : public PluginHost::IPlugin - { - public: - SceneSet(const SceneSet &) = delete; - SceneSet &operator=(const SceneSet &) = delete; - SceneSet(SceneSet &&) = delete; - SceneSet &operator=(SceneSet &&) = delete; - - SceneSet(); - - ~SceneSet() override = default; - - private: - class Configuration : public Core::JSON::Container - { - public: - Configuration() - : Core::JSON::Container(), refAppName() - { - Add(_T("refAppName"), &refAppName); - } - ~Configuration() = default; - - Configuration(Configuration &&) = delete; - Configuration(const Configuration &) = delete; - Configuration &operator=(Configuration &&) = delete; - Configuration &operator=(const Configuration &) = delete; - - public: - Core::JSON::String refAppName; - }; - - class NotificationHandler : public Exchange::IAppManager::INotification - { - - public: - NotificationHandler(SceneSet &parent) : mParent(parent) {} - ~NotificationHandler() {} - - void OnAppLifecycleStateChanged(const string &appId, const string &appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) - { - mParent.OnAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - } - - BEGIN_INTERFACE_MAP(NotificationHandler) - INTERFACE_ENTRY(Exchange::IAppManager::INotification) - END_INTERFACE_MAP - - private: - SceneSet &mParent; - }; - - public: - // IPlugin Methods - const string Initialize(PluginHost::IShell *service) override; - void Deinitialize(PluginHost::IShell *service) override; - string Information() const override; - - // Handle App Manager lifecycle state changes - void OnAppLifecycleStateChanged(const string &appId, const string &appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason); - - BEGIN_INTERFACE_MAP(SceneSet) - INTERFACE_ENTRY(PluginHost::IPlugin) - END_INTERFACE_MAP - - private: - std::string mrefAppName; - PluginHost::IShell *mService; - - // App Manager interface pointer - Exchange::IAppManager *mAppManager; - Core::Sink mNotification; - - void StartReferenceApp(); - void MonitorReferenceAppCrash(); - void RestartReferenceApp(); - }; - } // Plugin -} // WPEFramework diff --git a/SharedStorage/CHANGELOG.md b/SharedStorage/CHANGELOG.md deleted file mode 100644 index 140a1d0..0000000 --- a/SharedStorage/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. diff --git a/SharedStorage/CMakeLists.txt b/SharedStorage/CMakeLists.txt deleted file mode 100644 index 8302f45..0000000 --- a/SharedStorage/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2022 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required(VERSION 3.14) - -set(PLUGIN_NAME SharedStorage) -find_package(WPEFramework NAMES WPEFramework Thunder) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(CMAKE_CXX_STANDARD 11) - -set(PLUGIN_SHAREDSTORAGE_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_SHAREDSTORAGE_STARTUPORDER "51" CACHE STRING "To configure startup order of the plugin") - -add_library(${MODULE_NAME} SHARED - SharedStorage.cpp - Module.cpp -) - -include_directories( - ../helpers) - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -target_link_libraries(${MODULE_NAME} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) -add_library(${PLUGIN_IMPLEMENTATION} SHARED - Module.cpp - SharedStorageImplementation.cpp -) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions -) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/SharedStorage/Module.cpp b/SharedStorage/Module.cpp deleted file mode 100644 index ce759b6..0000000 --- a/SharedStorage/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/SharedStorage/Module.h b/SharedStorage/Module.h deleted file mode 100644 index 07f8ce6..0000000 --- a/SharedStorage/Module.h +++ /dev/null @@ -1,28 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_SharedStorage -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/SharedStorage/SharedStorage.conf.in b/SharedStorage/SharedStorage.conf.in deleted file mode 100644 index 0c1f17c..0000000 --- a/SharedStorage/SharedStorage.conf.in +++ /dev/null @@ -1,10 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.SharedStorage" -startuporder = "@PLUGIN_SHAREDSTORAGE_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_SHAREDSTORAGE_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) diff --git a/SharedStorage/SharedStorage.config b/SharedStorage/SharedStorage.config deleted file mode 100644 index d55f0f1..0000000 --- a/SharedStorage/SharedStorage.config +++ /dev/null @@ -1,16 +0,0 @@ -set(autostart true) -set(preconditions Platform) -set(callsign "org.rdk.SharedStorage") - -if(PLUGIN_SHAREDSTORAGE_STARTUPORDER) -set (startuporder ${PLUGIN_SHAREDSTORAGE_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_SHAREDSTORAGE_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) diff --git a/SharedStorage/SharedStorage.cpp b/SharedStorage/SharedStorage.cpp deleted file mode 100644 index ff7b514..0000000 --- a/SharedStorage/SharedStorage.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SharedStorage.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 1 - -namespace WPEFramework { - -namespace Plugin { - - namespace { - - static Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {}); - } - - SERVICE_REGISTRATION(SharedStorage, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - const string SharedStorage::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(service != nullptr); - ASSERT(_store2 == nullptr); - ASSERT(_storeInspector == nullptr); - ASSERT(_storeLimit == nullptr); - ASSERT(_storeCache == nullptr); - ASSERT(_service == nullptr); - ASSERT(_connectionId == 0); - - SYSLOG(Logging::Startup, (_T("SharedStorage::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - - _service->Register(&_notification); - - _store2 = _service->Root(_connectionId, RPC::CommunicationTimeOut, _T("SharedStorageImplementation")); - if (_store2 != nullptr) { - configure = _store2->QueryInterface(); - if (configure != nullptr) - { - uint32_t result = configure->Configure(_service); - if(result != Core::ERROR_NONE) - { - message = _T("SharedStorage could not be configured"); - } - } - else - { - message = _T("SharedStorage implementation did not provide a configuration interface"); - } - - Exchange::JSharedStorage::Register(*this, _store2); - _store2->Register(&_store2Sink); - } - else { - message = _T("Couldn't create _store2 implementation instance"); - } - if(message != "") - { - return message; - } - - _storeInspector = _store2->QueryInterface(); - if (_storeInspector != nullptr) { - Exchange::JSharedStorageInspector::Register(*this, _storeInspector); - } - else { - message = _T("Couldn't create _storeInspector implementation instance - 2"); - return message; - } - - _storeLimit = _store2->QueryInterface(); - if (_storeLimit != nullptr) { - Exchange::JSharedStorageLimit::Register(*this, _storeLimit); - } - else { - message = _T("Couldn't create _storeLimit implementation instance"); - return message; - } - _storeCache = _store2->QueryInterface(); - if (_storeCache != nullptr) { - Exchange::JSharedStorageCache::Register(*this, _storeCache); - } - else { - message = _T("Couldn't create _storeCache implementation instance"); - return message; - } - - return message; - } - - void SharedStorage::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("SharedStorage::Deinitialize")))); - - _service->Unregister(&_notification); - - if (_store2 != nullptr) { - _store2->Unregister(&_store2Sink); - Exchange::JSharedStorage::Unregister(*this); - configure->Release(); - configure = nullptr; - - auto connection = _service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED auto result = _store2->Release(); - _store2 = nullptr; - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - if (connection != nullptr) { - connection->Terminate(); - connection->Release(); - } - } - if (_storeInspector != nullptr) { - Exchange::JSharedStorageInspector::Unregister(*this); - } - if (_storeLimit != nullptr) { - Exchange::JSharedStorageLimit::Unregister(*this); - } - if (_storeCache != nullptr) { - Exchange::JSharedStorageCache::Unregister(*this); - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("SharedStorage de-initialised")))); - } - - string SharedStorage::Information() const - { - return (string()); - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/SharedStorage/SharedStorage.h b/SharedStorage/SharedStorage.h deleted file mode 100644 index 9dc6869..0000000 --- a/SharedStorage/SharedStorage.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class SharedStorage : public PluginHost::IPlugin, public PluginHost::JSONRPC { - private: - class Store2Notification : public Exchange::ISharedStorage::INotification { - private: - Store2Notification(const Store2Notification&) = delete; - Store2Notification& operator=(const Store2Notification&) = delete; - - public: - explicit Store2Notification(SharedStorage& parent) - : _parent(parent) - { - } - ~Store2Notification() override = default; - - public: - void OnValueChanged(const Exchange::ISharedStorage::ScopeType scope, const string& ns, const string& key, const string& value) override - { - SYSLOG(Logging::Startup, (_T("SharedStorage OnValueChanged"))); - Exchange::JSharedStorage::Event::OnValueChanged(_parent, scope, ns, key, value); - } - - BEGIN_INTERFACE_MAP(Store2Notification) - INTERFACE_ENTRY(Exchange::ISharedStorage::INotification) - END_INTERFACE_MAP - - private: - SharedStorage& _parent; - }; - - class RemoteConnectionNotification : public RPC::IRemoteConnection::INotification { - private: - RemoteConnectionNotification() = delete; - RemoteConnectionNotification(const RemoteConnectionNotification&) = delete; - RemoteConnectionNotification& operator=(const RemoteConnectionNotification&) = delete; - - public: - explicit RemoteConnectionNotification(SharedStorage& parent) - : _parent(parent) - { - } - ~RemoteConnectionNotification() override = default; - - BEGIN_INTERFACE_MAP(RemoteConnectionNotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - } - void Deactivated(RPC::IRemoteConnection* connection) override - { - if (connection->Id() == _parent._connectionId) { - ASSERT(_parent._service != nullptr); - Core::IWorkerPool::Instance().Schedule( - Core::Time::Now(), - PluginHost::IShell::Job::Create( - _parent._service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - private: - SharedStorage& _parent; - }; - - private: - SharedStorage(const SharedStorage&) = delete; - SharedStorage& operator=(const SharedStorage&) = delete; - - public: - SharedStorage() - : PluginHost::JSONRPC() - , _service(nullptr) - , _connectionId(0) - , _store2(nullptr) - , _store2Sink(*this) - , _notification(*this) - , _storeInspector(nullptr) - , _storeLimit(nullptr) - , _storeCache(nullptr) - { - } - ~SharedStorage() override = default; - - BEGIN_INTERFACE_MAP(SharedStorage) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::ISharedStorage, _store2) - INTERFACE_AGGREGATE(Exchange::ISharedStorageInspector, _storeInspector) - INTERFACE_AGGREGATE(Exchange::ISharedStorageLimit, _storeLimit) - INTERFACE_AGGREGATE(Exchange::ISharedStorageCache, _storeCache) - END_INTERFACE_MAP - - public: - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - PluginHost::IShell* _service; - uint32_t _connectionId; - Exchange::ISharedStorage* _store2; - Core::Sink _store2Sink; - Core::Sink _notification; - Exchange::IConfiguration* configure; - Exchange::ISharedStorageInspector* _storeInspector; - Exchange::ISharedStorageLimit* _storeLimit; - Exchange::ISharedStorageCache* _storeCache; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/SharedStorage/SharedStorageImplementation.cpp b/SharedStorage/SharedStorageImplementation.cpp deleted file mode 100644 index 10f4f90..0000000 --- a/SharedStorage/SharedStorageImplementation.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SharedStorageImplementation.h" -#include "UtilsLogging.h" - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(SharedStorageImplementation, 1, 0); - - SharedStorageImplementation::SharedStorageImplementation() : - _adminLock() - , _service(nullptr) - , _storeNotification(*this) - , _psObject(nullptr) - , _psInspector(nullptr) - , _psLimit(nullptr) - , _psCache(nullptr) - , _csObject(nullptr) - { - LOGINFO("SharedStorageImplementation constructor - 3"); - } - - SharedStorageImplementation::~SharedStorageImplementation() - { - LOGINFO("SharedStorageImplementation destructor"); - if(_psObject) - { - _psObject->Release(); - } - if(_psInspector) - { - _psInspector->Release(); - } - if(_psLimit) - { - _psLimit->Release(); - } - if(_psCache) - { - _psCache->Release(); - } - if(_csObject) - { - _csObject->Release(); - } - if (_service != nullptr) - { - _service->Release(); - _service = nullptr; - } - } - - SharedStorageImplementation* SharedStorageImplementation::instance(SharedStorageImplementation *SharedStorageImpl) - { - LOGINFO("SharedStorageImplementation instance"); - static SharedStorageImplementation *SharedStorageImpl_instance = nullptr; - - if (SharedStorageImpl != nullptr) - { - SharedStorageImpl_instance = SharedStorageImpl; - } - else - { - LOGERR("SharedStorageImpl is null \n"); - } - return(SharedStorageImpl_instance); - } - - uint32_t SharedStorageImplementation::Register(ISharedStorage::INotification* notification) - { - // Make sure we can't register the same notification callback multiple times - if (std::find(_sharedStorageNotification.begin(), _sharedStorageNotification.end(), notification) == _sharedStorageNotification.end()) - { - LOGINFO("Register notification"); - _sharedStorageNotification.push_back(notification); - notification->AddRef(); - } - else - { - LOGERR("notification is already available in the _sharedStorageNotification"); - } - - return Core::ERROR_NONE; - } - - uint32_t SharedStorageImplementation::Unregister(ISharedStorage::INotification* notification) - { - uint32_t status = Core::ERROR_GENERAL; - - // Make sure we can't unregister the same notification callback multiple times - auto itr = std::find(_sharedStorageNotification.begin(), _sharedStorageNotification.end(), notification); - - if (itr != _sharedStorageNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - _sharedStorageNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - return status; - } - - uint32_t SharedStorageImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_GENERAL; - - if (service != nullptr) - { - _service = service; - _service->AddRef(); - result = Core::ERROR_NONE; - - // Get interface for IStore2 - _psObject = service->QueryInterfaceByCallsign("org.rdk.PersistentStore"); - if (_psObject != nullptr) - { - _psObject->Register(&_storeNotification); - } - else - { - LOGERR("_psObject is null \n"); - } - _psInspector = service->QueryInterfaceByCallsign("org.rdk.PersistentStore"); - if(_psInspector == nullptr) - { - LOGERR("_psInspector is null \n"); - } - else - { - LOGINFO("_psInspector success "); - } - _psLimit = service->QueryInterfaceByCallsign("org.rdk.PersistentStore"); - if(_psLimit == nullptr) - { - LOGERR("_psLimit is null \n"); - } - else - { - LOGINFO("_psLimit success "); - } - _psCache = service->QueryInterfaceByCallsign("org.rdk.PersistentStore"); - if(_psCache == nullptr) - { - LOGERR("_psCache is null \n"); - } - else - { - LOGINFO("_psCache success "); - } - - // Establish communication with CloudStore - _csObject = service->QueryInterfaceByCallsign("org.rdk.CloudStore"); - if (_csObject != nullptr) - { - _csObject->Register(&_storeNotification); - } - else - { - LOGERR("_csObject is null \n"); - } - } - else - { - LOGERR("service is null \n"); - } - - return result; - } - - Exchange::IStore2* SharedStorageImplementation::getRemoteStoreObject(const Exchange::ISharedStorageLimit::ScopeType eScope) - { - if( (eScope == WPEFramework::Exchange::ISharedStorageLimit::ScopeType::DEVICE) && _psObject) - { - return _psObject; - } - else if( (eScope == WPEFramework::Exchange::ISharedStorageLimit::ScopeType::ACCOUNT) && _csObject) - { - return _csObject; - } - else - { - TRACE(Trace::Error, (_T("%s: Unknown scope: %d"), __FUNCTION__, static_cast(eScope))); - return nullptr; - } - } - - void SharedStorageImplementation::ValueChanged(const Exchange::ISharedStorage::ScopeType eScope, const string& ns, const string& key, const string& value) - { - LOGINFO("ns:%s key:%s value:%s", ns.c_str(), key.c_str(), value.c_str()); - JsonObject params; - params["namespace"] = ns; - params["key"] = key; - params["value"] = value; - params["scope"] = static_cast(eScope); - dispatchEvent(SHAREDSTORAGE_EVT_VALUE_CHANGED, params); - } - - void SharedStorageImplementation::dispatchEvent(Event event, const JsonObject ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void SharedStorageImplementation::Dispatch(Event event, const JsonObject ¶ms) - { - _adminLock.Lock(); - - std::list::const_iterator index(_sharedStorageNotification.begin()); - - while (index != _sharedStorageNotification.end()) - { - string ns = params["namespace"].String(); - string key = params["key"].String(); - string value = params["value"].String(); - uint8_t scopeVal = static_cast(params["scope"].Number()); - Exchange::ISharedStorage::ScopeType scope = static_cast(scopeVal); - - (*index)->OnValueChanged(scope,ns,key,value); - index++; - } - - _adminLock.Unlock(); -} - - uint32_t SharedStorageImplementation::SetValue(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, const string& value, const uint32_t ttl, Success& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success.success = false; - Exchange::IStore2* _storeObject = getRemoteStoreObject(eScope); - ASSERT (nullptr != _storeObject); - if (nullptr != _storeObject) - { - status = _storeObject->SetValue( - (Exchange::IStore2::ScopeType)eScope, - ns, - key, - value, - ttl); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success.success = true; - } - } - return status; - } - uint32_t SharedStorageImplementation::GetValue(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, string& value, uint32_t& ttl, bool& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success = false; - Exchange::IStore2* _storeObject = getRemoteStoreObject(eScope); - ASSERT (nullptr != _storeObject); - if (nullptr != _storeObject) - { - status = _storeObject->GetValue( - (Exchange::IStore2::ScopeType)eScope, - ns, - key, - value, - ttl); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success = true; - } - } - return status; - } - uint32_t SharedStorageImplementation::DeleteKey(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, Success& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success.success = false; - Exchange::IStore2* _storeObject = getRemoteStoreObject(eScope); - ASSERT (nullptr != _storeObject); - if (nullptr != _storeObject) - { - status = _storeObject->DeleteKey( - (Exchange::IStore2::ScopeType)eScope, - ns, - key); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success.success = true; - } - } - return status; - } - uint32_t SharedStorageImplementation::DeleteNamespace(const ISharedStorage::ScopeType eScope, const string& ns, Success& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success.success = false; - Exchange::IStore2* _storeObject = getRemoteStoreObject(eScope); - ASSERT (nullptr != _storeObject); - if (nullptr != _storeObject) - { - status = _storeObject->DeleteNamespace( - (Exchange::IStore2::ScopeType)eScope, - ns); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success.success = true; - } - } - return status; - } - - uint32_t SharedStorageImplementation::GetKeys(const ISharedStorageInspector::ScopeType eScope, const string& ns, RPC::IStringIterator*& keys, bool& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success = false; - LOGINFO("Scope-2:%d ns:%s", static_cast(eScope), ns.c_str()); - if(eScope != ISharedStorageInspector::ScopeType::DEVICE) - { - LOGINFO("Scope is not DEVICE"); - return status; - } - status = Core::ERROR_GENERAL; - ASSERT (nullptr != _psInspector); - if (nullptr != _psInspector) - { - LOGINFO("_psInspector is not null"); - status = _psInspector->GetKeys((Exchange::IStore2::ScopeType)eScope, ns, keys); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success = true; - } - } - else - { - LOGINFO("_psInspector is null"); - } - return status; - } - - uint32_t SharedStorageImplementation::GetNamespaces(const ISharedStorageInspector::ScopeType eScope, RPC::IStringIterator*& namespaces, bool& success) - { - uint32_t status = Core::ERROR_NOT_SUPPORTED; - success = false; - if(eScope != ISharedStorageInspector::ScopeType::DEVICE) - { - return status; - } - status = Core::ERROR_GENERAL; - ASSERT (nullptr != _psInspector); - if (nullptr != _psInspector) - { - status = _psInspector->GetNamespaces((Exchange::IStore2::ScopeType)eScope, namespaces); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success = true; - } - } - return status; - } - - Core::hresult SharedStorageImplementation::GetStorageSizes(const ISharedStorageInspector::ScopeType eScope, INamespaceSizeIterator*& storageList, bool& success) - { - Core::hresult status = Core::ERROR_NOT_SUPPORTED; - success = false; - if(eScope != ISharedStorageInspector::ScopeType::DEVICE) - { - return status; - } - status = Core::ERROR_GENERAL; - ASSERT (nullptr != _psInspector); - if (nullptr != _psInspector) - { - status = _psInspector->GetStorageSizes((Exchange::IStore2::ScopeType)eScope, (WPEFramework::Exchange::IStoreInspector::INamespaceSizeIterator*&)storageList); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - else - { - success = true; - } - } - return status; - } - - Core::hresult SharedStorageImplementation::SetNamespaceStorageLimit(const ISharedStorageLimit::ScopeType eScope, const string& ns, const uint32_t storageLimit, bool& success) - { - Core::hresult status = Core::ERROR_NOT_SUPPORTED; - if(eScope != ISharedStorageLimit::ScopeType::DEVICE) - { - return status; - } - status = Core::ERROR_GENERAL; - ASSERT(nullptr != _psLimit); - if(_psLimit != nullptr) - { - status = _psLimit->SetNamespaceStorageLimit((Exchange::IStore2::ScopeType)eScope, ns, storageLimit); - } - success = (status == Core::ERROR_NONE); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - return status; - } - - Core::hresult SharedStorageImplementation::GetNamespaceStorageLimit(const ISharedStorageLimit::ScopeType eScope, const string& ns, StorageLimit& storageLimit) - { - Core::hresult status = Core::ERROR_NOT_SUPPORTED; - if(eScope != ISharedStorageLimit::ScopeType::DEVICE) - { - return status; - } - status = Core::ERROR_GENERAL; - ASSERT(nullptr != _psLimit); - if(_psLimit != nullptr) - { - status = _psLimit->GetNamespaceStorageLimit((Exchange::IStore2::ScopeType)eScope, ns, storageLimit.storageLimit); - } - - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - return status; - } - - Core::hresult SharedStorageImplementation::FlushCache() - { - Core::hresult status = Core::ERROR_GENERAL; - ASSERT(nullptr != _psCache); - if(_psCache != nullptr) - { - status = _psCache->FlushCache(); - if (status != Core::ERROR_NONE) { - TRACE(Trace::Error, (_T("%s: Status: %d"), __FUNCTION__, status)); - } - } - return status; - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/SharedStorage/SharedStorageImplementation.h b/SharedStorage/SharedStorageImplementation.h deleted file mode 100644 index 218f601..0000000 --- a/SharedStorage/SharedStorageImplementation.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class SharedStorageImplementation : public Exchange::ISharedStorage, - public Exchange::ISharedStorageInspector, - public Exchange::ISharedStorageLimit, - public Exchange::ISharedStorageCache, - public Exchange::IConfiguration { - private: - SharedStorageImplementation(const SharedStorageImplementation&) = delete; - SharedStorageImplementation& operator=(const SharedStorageImplementation&) = delete; - - private: - class Store2Notification : public Exchange::IStore2::INotification { - private: - Store2Notification(const Store2Notification&) = delete; - Store2Notification& operator=(const Store2Notification&) = delete; - - public: - explicit Store2Notification(SharedStorageImplementation& parent) - : _parent(parent) - { - } - ~Store2Notification() override = default; - - public: - void ValueChanged(const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value) override - { - SYSLOG(Logging::Shutdown, (string(_T("SharedStorageImpl::ValueChanged")))); - _parent.ValueChanged((ISharedStorage::ScopeType)scope, ns, key, value); - } - - BEGIN_INTERFACE_MAP(Store2Notification) - INTERFACE_ENTRY(Exchange::IStore2::INotification) - END_INTERFACE_MAP - - private: - SharedStorageImplementation& _parent; - }; - - public: - SharedStorageImplementation(); - ~SharedStorageImplementation() override; - static SharedStorageImplementation* instance(SharedStorageImplementation *SharedStorageImpl = nullptr); - BEGIN_INTERFACE_MAP(SharedStorageImplementation) - INTERFACE_ENTRY(Exchange::ISharedStorage) - INTERFACE_ENTRY(ISharedStorageInspector) - INTERFACE_ENTRY(ISharedStorageLimit) - INTERFACE_ENTRY(ISharedStorageCache) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - public: - enum Event - { - SHAREDSTORAGE_EVT_VALUE_CHANGED - }; - - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(SharedStorageImplementation* sharedStorageImplementation, Event event, JsonObject& params) - : _sharedStorageImplementation(sharedStorageImplementation) - , _event(event) - , _params(params) { - if (_sharedStorageImplementation != nullptr) { - _sharedStorageImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (_sharedStorageImplementation != nullptr) { - _sharedStorageImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(SharedStorageImplementation* sharedStorageImplementation, Event event, JsonObject params) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(sharedStorageImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(sharedStorageImplementation, event, params))); -#endif - } - - virtual void Dispatch() { - _sharedStorageImplementation->Dispatch(_event, _params); - } - - private: - SharedStorageImplementation *_sharedStorageImplementation; - const Event _event; - const JsonObject _params; - }; - - private: - // IConfiguration interface - Core::hresult Configure(PluginHost::IShell* service) override; - Core::hresult Register(ISharedStorage::INotification* notification) override; - Core::hresult Unregister(ISharedStorage::INotification* notification) override; - - //ISharedStorage APIs - Core::hresult SetValue(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, const string& value, const uint32_t ttl, Success& success) override; - Core::hresult GetValue(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, string& value, uint32_t& ttl, bool& success) override; - Core::hresult DeleteKey(const ISharedStorage::ScopeType eScope, const string& ns, const string& key, Success& success) override; - Core::hresult DeleteNamespace(const ISharedStorage::ScopeType eScope, const string& ns, Success& success) override; - - //ISharedStorageInspector APIs - Core::hresult GetKeys(const ISharedStorageInspector::ScopeType eScope, const string& ns, RPC::IStringIterator*& keys, bool& success) override; - Core::hresult GetNamespaces(const ISharedStorageInspector::ScopeType eScope, RPC::IStringIterator*& namespaces, bool& success) override; - Core::hresult GetStorageSizes(const ISharedStorageInspector::ScopeType eScope, INamespaceSizeIterator*& storageList, bool& success) override; - - //ISharedStorageLimit APIs - Core::hresult SetNamespaceStorageLimit(const ISharedStorageLimit::ScopeType eScope, const string& ns, const uint32_t storageLimit, bool& success) override; - Core::hresult GetNamespaceStorageLimit(const ISharedStorageLimit::ScopeType eScope, const string& ns, StorageLimit& storageLimit) override; - - //ISharedStorageCache APIs - Core::hresult FlushCache() override; - - Exchange::IStore2* getRemoteStoreObject(const Exchange::ISharedStorageLimit::ScopeType eScope); - void ValueChanged(const Exchange::ISharedStorage::ScopeType eScope, const string& ns, const string& key, const string& value); - - void dispatchEvent(Event, const JsonObject ¶ms); - void Dispatch(Event event, const JsonObject ¶ms); - - private: - mutable Core::CriticalSection _adminLock; - PluginHost::IShell* _service; - Core::Sink _storeNotification; - Exchange::IStore2* _psObject; - Exchange::IStoreInspector* _psInspector; - Exchange::IStoreLimit* _psLimit; - Exchange::IStoreCache* _psCache; - Exchange::IStore2* _csObject; - std::list _sharedStorageNotification; - - public: - friend class Job; -}; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/StorageManager/CHANGELOG.md b/StorageManager/CHANGELOG.md deleted file mode 100755 index 2e200c4..0000000 --- a/StorageManager/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/StorageManager/CMakeLists.txt b/StorageManager/CMakeLists.txt deleted file mode 100755 index 7770de2..0000000 --- a/StorageManager/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME StorageManager) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_STORAGE_MANAGER_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_STORAGE_MANAGER_AUTOSTART false CACHE STRING "Automatically start StorageManager plugin") -set(PLUGIN_STORAGE_MANAGER_EXTRA_LIBRARIES "") -set(PLUGIN_STORAGE_MANAGER_STARTUPORDER "" CACHE STRING "Automatically start StorageManager plugin") - -option(AIMANAGERS_TELEMETRY_METRICS_SUPPORT "AIMANAGERS_TELEMETRY_METRICS_SUPPORT" OFF) - -add_definitions(-DSTORAGE_MANAGER_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DSTORAGE_MANAGER_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DSTORAGE_MANAGER_API_VERSION_NUMBER_PATCH=0) - -set(STORAGE_MANAGER_IMPLEMENTATION ${PLUGIN_NAME}Implementation) -add_definitions(-DPLUGIN_STORAGE_MANAGER_IMPLEMENTATION_NAME="${STORAGE_MANAGER_IMPLEMENTATION}") -set(PLUGIN_STORAGE_MANAGER_PATH "/opt/persistent/storageManager" CACHE STRING "Path") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - StorageManager.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(StorageManager.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - StorageManagerImplementation.cpp - RequestHandler.cpp - Module.cpp) - -if(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - message(STATUS "TELEMETRY_METRICS_SUPPORT is enabled") - add_definitions(-DENABLE_AIMANAGERS_TELEMETRY_METRICS) -endif(AIMANAGERS_TELEMETRY_METRICS_SUPPORT) - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set(STORAGE_MANAGER_INCLUDES $ENV{STORAGE_MANAGER_INCLUDES}) -separate_arguments(STORAGE_MANAGER_INCLUDES) -include_directories(BEFORE ${STORAGE_MANAGER_INCLUDES}) - -if (RDK_SERVICES_L1_TEST) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,open -Wl,--wrap,mkdir -Wl,--wrap,access -Wl,--wrap,nftw -Wl,--wrap,statvfs -Wl,--wrap,rmdir -Wl,--wrap,chown -Wl,--wrap,opendir -Wl,--wrap,readdir -Wl,--wrap,stat -Wl,--wrap,closedir) -endif (RDK_SERVICES_L1_TEST) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,statvfs -Wl,--wrap,chown -Wl,--wrap,access) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_STORAGE_MANAGER_EXTRA_LIBRARIES}) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/StorageManager/Module.cpp b/StorageManager/Module.cpp deleted file mode 100755 index cd6d4d1..0000000 --- a/StorageManager/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/StorageManager/Module.h b/StorageManager/Module.h deleted file mode 100755 index fbe56e0..0000000 --- a/StorageManager/Module.h +++ /dev/null @@ -1,31 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_StorageManager -#endif - -#include -#include - -#define PATH_ENV "STORAGE_MANAGER_PATH" - -#undef EXTERNAL -#define EXTERNAL diff --git a/StorageManager/README.md b/StorageManager/README.md deleted file mode 100755 index 42c9f03..0000000 --- a/StorageManager/README.md +++ /dev/null @@ -1,26 +0,0 @@ ------------------ -# StorageManager - -## Versions -`org.rdk.StorageManager.1` - -## Methods: -``` -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method": "org.rdk.StorageManager.clear", "params": {"appId": "com.sky.testapp"}}' http://127.0.0.1:9998/jsonrpc -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0", "id":3, "method": "org.rdk.StorageManager.clearAll", "params": {"exemptionAppIds": "com.sky.testapp"}}' http://127.0.0.1:9998/jsonrpc -``` - -## Responses -``` -clear: -{"jsonrpc":"2.0","id":3,"result":""} - -clearAll: -{"jsonrpc":"2.0","id":3,"result":""} - -``` - -## Events -``` -none -``` diff --git a/StorageManager/RequestHandler.cpp b/StorageManager/RequestHandler.cpp deleted file mode 100755 index 094e71f..0000000 --- a/StorageManager/RequestHandler.cpp +++ /dev/null @@ -1,947 +0,0 @@ - -#include -#include -#include "RequestHandler.h" -#include "UtilsLogging.h" -#include -#include - -#define MAX_NUM_OF_FILE_DESCRIPTORS 256 -#define DEFAULT_STORAGE_DEV_BLOCK_SIZE 512 -#define STORAGE_DIR_PERMISSION 0755 - - -namespace WPEFramework -{ - namespace Plugin - { - std::mutex mInstanceMutex; - static RequestHandler::StorageSize gStorageSize; - std::mutex RequestHandler::mStorageSizeLock; - - RequestHandler& RequestHandler::getInstance() - { - static RequestHandler instance; - return instance; - } - - RequestHandler::RequestHandler(): mService(nullptr) - ,mStorageManagerImplLock() - ,mPersistentStoreRemoteStoreObject(nullptr) - { - LOGINFO("Create RequestHandler Instance"); - } - - RequestHandler::~RequestHandler() - { - LOGINFO("Delete RequestHandler Instance"); - } - - void RequestHandler::setCurrentService(PluginHost::IShell* service) - { - if (service != nullptr) - { - mService = service; - } - else - { - LOGERR("mService is null \n"); - } - } - - Core::hresult RequestHandler::populateAppInfoCacheFromStoragePath() - { - Core::hresult status = Core::ERROR_GENERAL; - std::string errorReason; - - DIR* dir = opendir(mBaseStoragePath.c_str()); - if (!dir) - { - LOGERR("Failed to open storage directory: %s. Error: %s", mBaseStoragePath.c_str(), strerror(errno)); - } - else - { - struct dirent* entry; - while ((entry = readdir(dir)) != nullptr) - { - LOGINFO("entry->d_name: %s", entry->d_name); - if (entry->d_type != DT_DIR || strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || !isValidAppStorageDirectory(entry->d_name)) - { - LOGERR("entry->d_name: %s d_type : %d - not a directory, it is [.] or [..], or invalid appId - SKIPPED\n", entry->d_name, entry->d_type); - continue; - } - - std::string appId = entry->d_name; - - //capture the path - std::string appFilePath = mBaseStoragePath + '/' + appId; - - //get the uid, gid by stat - struct stat dirStat; - if (stat(appFilePath.c_str(), &dirStat) == -1) - { - LOGERR("unable to get the status of app directory. appFilePath: %s", appFilePath.c_str()); - continue; - } - - //update the StorageAppInfo object and populate the Map - StorageAppInfo storageInfo; - storageInfo.path = std::move(appFilePath); - storageInfo.uid = static_cast(dirStat.st_uid); - storageInfo.gid = static_cast(dirStat.st_gid); - - //get the quotaKB - status = appQuotaSizeProperty(GET, appId, &storageInfo.quotaKB); - if (Core::ERROR_NONE != status) - { - LOGERR("appQuotaSizeProperty Failed for App Quota size retrivel, appId:%s!!!", appId.c_str()); - storageInfo.quotaKB = 0; - } - - storageInfo.usedKB = static_cast(getDirectorySizeInBytes(storageInfo.path) / 1024); //get the used size - - LOGINFO("Retrieved storageInfo for appId: %s " \ - "userId: %d groupId: %d quotaKB: %u usedKB: %u path: %s", - appId.c_str(), storageInfo.uid, storageInfo.gid, storageInfo.quotaKB, storageInfo.usedKB, storageInfo.path.c_str()); - - if(!createAppStorageInfoByAppID(appId,storageInfo)) - { - LOGERR("Failed to create storage at mStorageAppInfo\n"); - status = Core::ERROR_GENERAL; - } - } - closedir(dir); - } - return status; - } - - Core::hresult RequestHandler::createPersistentStoreRemoteStoreObject() - { - Core::hresult status = Core::ERROR_GENERAL; - LOGINFO("Entered createPersistentStoreRemoteStoreObject"); - LOGINFO("mService: %p", mService); - if (nullptr == mService) - { - LOGERR("mService is null \n"); - } - else if (nullptr == (mPersistentStoreRemoteStoreObject = mService->QueryInterfaceByCallsign("org.rdk.PersistentStore"))) - { - LOGERR("mPersistentStoreRemoteStoreObject is null \n"); - } - else - { - LOGINFO("created PersistentStore Object\n"); - status = Core::ERROR_NONE; - } - return status; - } - - void RequestHandler::releasePersistentStoreRemoteStoreObject() - { - ASSERT(nullptr != mPersistentStoreRemoteStoreObject); - if(mPersistentStoreRemoteStoreObject) - { - mPersistentStoreRemoteStoreObject->Release(); - mPersistentStoreRemoteStoreObject = nullptr; - } - } - - - /*** - * @brief: Validate the given directory name is a proper AppID. - * - * The rules are that only dots (.), dashes (-), underscore (_) and - * alphanumeric characters are allow, with the following additional restrictions: - * - the first and last characters must be alphanumeric - * - double dots (..) are not allowed - * - * @param[in] dirName : App identifier for the application - * - * @return : bool - ***/ - bool RequestHandler::isValidAppStorageDirectory(const std::string& dirName) - { - if (dirName.empty()) - return false; - - auto it = dirName.begin(); - char ch = *it++; - if (!isalnum(ch)) - { - return false; - } - - for (; it != dirName.end(); ++it) - { - char prev = ch; - ch = *it; - - // check for double dots - if (ch == '.') - { - if (prev == '.') - return false; - } - else if (!isalnum(ch) && (ch != '-') && (ch != '_')) - { - return false; - } - } - - // check the last character is alphanumeric - return isalnum(ch); - } - - - /*** - * @brief Get / Set / Delete the QuotaSize property for the given app. - * Handles persistent property for a given app based on the appId and key. - * - * @param[in] appId : App identifier for the application - * @param[in] StorageActionType : SET/ GET / DELETE Action to be performed on the property - * @param[in/out] value : value of the QuataSize, based on the ActionType value set or retrieved. - * - * @return : Core:: - */ - - Core::hresult RequestHandler::appQuotaSizeProperty(RequestHandler::StorageActionType actionType, const std::string& appId, uint32_t* quotaValue) - { - Core::hresult status = Core::ERROR_GENERAL; - const std::string key = "quotaSize"; - uint32_t ttl = 0; - - /* Check if appId is empty */ - if (appId.empty()) - { - LOGERR("App ID is empty"); - } - else - { - /* Ensure the persistent store object is created if necessary */ - if (mPersistentStoreRemoteStoreObject == nullptr && Core::ERROR_NONE != createPersistentStoreRemoteStoreObject()) - { - LOGERR("Failed to create PersistentStoreRemoteStoreObject"); - status = Core::ERROR_GENERAL; // Set status to indicate failure - } - else - { - ASSERT(mPersistentStoreRemoteStoreObject != nullptr); - - /* Perform action based on the StorageActionType */ - if (mPersistentStoreRemoteStoreObject != nullptr) - { - switch (actionType) - { - case SET: - { - status = mPersistentStoreRemoteStoreObject->SetValue(Exchange::IStore2::ScopeType::DEVICE, appId, key, std::to_string(*quotaValue), 0); - if (Core::ERROR_NONE != status) - { - LOGERR("SetValue Failed: appId[%s] Key[%s] status[%d]", appId.c_str(), key.c_str(), status); - } - else - { - LOGINFO("SetValue: appId[%s] Key[%s] value[%d]", appId.c_str(), key.c_str(), *quotaValue); - } - } - break; - - case GET: - { - std::string quotaSize; - status = mPersistentStoreRemoteStoreObject->GetValue(Exchange::IStore2::ScopeType::DEVICE, appId, key, quotaSize, ttl); - if (Core::ERROR_NONE != status) - { - LOGERR("GetValue Failed: appId[%s] Key[%s] status[%d]", appId.c_str(), key.c_str(), status); - } - else - { - LOGINFO("appId[%s] Key[%s] value retrived[%s]", appId.c_str(), key.c_str(), quotaSize.c_str()); - *quotaValue = static_cast(std::stoul(quotaSize,nullptr,0)); - } - } - break; - - case DELETE: - { - status = mPersistentStoreRemoteStoreObject->DeleteKey(Exchange::IStore2::ScopeType::DEVICE, appId, key); - if (Core::ERROR_NONE != status) - { - LOGERR("DeleteKey Failed: appId[%s] Key[%s] status[%d]", appId.c_str(), key.c_str(), status); - } - else - { - LOGINFO("appId[%s] Deleted Key[%s] ", appId.c_str(), key.c_str()); - } - } - break; - - default: - { - LOGERR("Invalid storage type : %d", actionType); - } - break; - } - } - } - } - - return status; - } - - /** - * @brief : Adds file sizes to calculate total storage usage. - */ - int RequestHandler::getSize(const char *path, const struct stat *statPtr, int currentFlag, struct FTW *internalFtwUsage ) - { - if (currentFlag == FTW_F && statPtr != nullptr) - { - std::lock_guard storageSizelock(mStorageSizeLock); - if (!gStorageSize.blockSize) - { - /* Check and Store the current storage dev block size */ - gStorageSize.blockSize = (0 != statPtr->st_blksize) ? statPtr->st_blksize : DEFAULT_STORAGE_DEV_BLOCK_SIZE; - LOGINFO("path: %s dev blksize:%lu blockSize is set to %llu", path, statPtr->st_blksize, gStorageSize.blockSize); - } - - // Calculate used bytes - uint64_t usedBytesForFile = ((uint64_t)statPtr->st_size > ((uint64_t)statPtr->st_blocks * (uint64_t)gStorageSize.blockSize)) ? - ((uint64_t)statPtr->st_blocks *(uint64_t)gStorageSize.blockSize) : - (uint64_t)statPtr->st_size; - gStorageSize.usedBytes += usedBytesForFile; - LOGINFO("path: %s usedBytes: %llu blockSize: %llu", path, gStorageSize.usedBytes, gStorageSize.blockSize); - } - (void)internalFtwUsage; - return 0; - } - - /** - * @brief : Get the directory size traversing through the given directory path - */ - uint64_t RequestHandler::getDirectorySizeInBytes(const std::string &path) - { - const int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS; - - std::unique_lock storageSizelock(mStorageSizeLock); - gStorageSize.usedBytes = 0; - storageSizelock.unlock(); - const int result = nftw(path.c_str(), getSize, MAX_NUM_OF_FILE_DESCRIPTORS, flags); - - if (result == -1) - { - LOGERR("nftw returned with [%d]", result); - } - storageSizelock.lock(); - return gStorageSize.usedBytes; - } - - /** - * @brief : Create or Update App storageInfo map entry for the given appId - */ - bool RequestHandler::createAppStorageInfoByAppID(const std::string& appId, StorageAppInfo &storageInfo) - { - bool result = false; - - if (storageInfo.path.empty()) - { - LOGWARN("AppId[%s] storage path is empty!", appId.c_str()); - } - else - { - /* Check if the appId exists */ - auto it = mStorageAppInfo.find(appId); - if (it != mStorageAppInfo.end()) - { - /* Update existing entry */ - it->second.path = storageInfo.path; - it->second.uid = storageInfo.uid; - it->second.gid = storageInfo.gid; - it->second.quotaKB = storageInfo.quotaKB; - LOGINFO("Existing storage entry updated for appId: %s " \ - "userId: %d groupId: %d quotaKB: %u usedKB: %u path: %s", - appId.c_str(), it->second.uid, it->second.gid, it->second.quotaKB, it->second.usedKB, it->second.path.c_str()); - } - else - { - /* Create new entry */ - mStorageAppInfo[appId].path = storageInfo.path; - mStorageAppInfo[appId].uid = storageInfo.uid; - mStorageAppInfo[appId].gid = storageInfo.gid; - mStorageAppInfo[appId].quotaKB = storageInfo.quotaKB; - mStorageAppInfo[appId].usedKB = storageInfo.usedKB; - LOGINFO("Created new storage entry for appId: %s " \ - "userId: %d groupId: %d quotaKB: %u usedKB: %u path: %s", - appId.c_str(), storageInfo.uid, storageInfo.gid, storageInfo.quotaKB, storageInfo.usedKB, storageInfo.path.c_str()); - } - result = true; - } - return result; - } - - /** - * @brief : c App StorageInfo for the given appId - * - * @return : True if App StorageInfo is available, false otherwise. - */ - bool RequestHandler::retrieveAppStorageInfoByAppID(const string &appId, StorageAppInfo &storageInfo) - { - bool result = false; - - /* Check if the appId exists */ - auto it = mStorageAppInfo.find(appId); - if (it != mStorageAppInfo.end()) - { - /* Check if the existing storage directory is accessible */ - if (access(it->second.path.c_str(), F_OK) == 0) - { - /* Updating the usedKB based on the directory size */ - it->second.usedKB = static_cast(getDirectorySizeInBytes(it->second.path) / 1024); - storageInfo.path = it->second.path; - storageInfo.uid = it->second.uid; - storageInfo.gid = it->second.gid; - storageInfo.quotaKB = it->second.quotaKB; - storageInfo.usedKB = it->second.usedKB; - LOGINFO("App storage entry found for appId: %s " \ - "userId: %d groupId: %d quotaKB: %u usedKB: %u path: %s", - appId.c_str(), storageInfo.uid, storageInfo.gid, storageInfo.quotaKB, storageInfo.usedKB, storageInfo.path.c_str()); - result = true; - } - else - { - /* Not accessible, need to remove existing storage entry forcibly, recreate it */ - if (removeAppStorageInfoByAppID(appId)) - { - LOGWARN("Storage path for appID[%s] not accessible - forcibly removed!", it->second.path.c_str()); - } - else - { - LOGERR("Failed to remove app storage entry forcibly: %s", it->second.path.c_str()); - } - } - } - else - { - LOGWARN("AppId[%s] storage entry not found/created", appId.c_str()); - } - return result; - } - - /** - * @brief : Remove App StorageInfo for the given appId - * - * @return : True if App StorageInfo map is available and erased, false otherwise. - */ - bool RequestHandler::removeAppStorageInfoByAppID(const string &appId) - { - bool result = false; - - /* Check if appId StorageInfo is found, erase it */ - auto it = mStorageAppInfo.find(appId); - if (it != mStorageAppInfo.end()) - { - LOGINFO("App storage entry erased for appId: %s " \ - "userId: %d groupId: %d quotaKB: %u usedKB: %u path: %s", - appId.c_str(), it->second.uid, it->second.gid, it->second.quotaKB, it->second.usedKB, it->second.path.c_str()); - mStorageAppInfo.erase(appId); - appQuotaSizeProperty(DELETE, appId, nullptr); //Remove the persistent store entry - result = true; - } - else - { - LOGWARN("AppId[%s] StorageInfo not found", appId.c_str()); - } - return result; - } - - /** - * @brief : Check whether enough storag space is to create a new app Directory. - * - * @return : True if enough space is available, false otherwise. - */ - bool RequestHandler::hasEnoughStorageFreeSpace(const std::string& baseDir, uint32_t requiredSpaceKB) - { - bool hasEnoughSpace = false; - struct statvfs statFs; - uint64_t curStorageFreeSpaceKB = 0; - uint64_t existingAppsReservationSpaceKB = 0; - int64_t availableSizeKB = 0; - - if (baseDir.empty()) - { - LOGERR("Invalid baseDir: path cannot be empty"); - } - else - { - if (statvfs(baseDir.c_str(), &statFs) == 0) - { - /* Store the current storage dev block size */ - { - std::lock_guard storageSizelock(mStorageSizeLock); - - gStorageSize.blockSize = (statFs.f_bsize != 0) ? statFs.f_bsize : DEFAULT_STORAGE_DEV_BLOCK_SIZE; /* Fallback to default block size */ - LOGINFO("path: %s f_bsize:%lu f_frsize:%lu, blockSize is set to %llu", baseDir.c_str(), statFs.f_bsize, statFs.f_frsize, gStorageSize.blockSize); - } - - /* Calculate the current available storage in KB */ - curStorageFreeSpaceKB = (static_cast(statFs.f_bfree) * statFs.f_frsize) / 1024; - - /* Compute total reserved space for existing applications */ - for (auto& entry : mStorageAppInfo) - { - entry.second.usedKB = static_cast(getDirectorySizeInBytes(entry.second.path) / 1024); - - /* Ensure applications do not exceed allocated space */ - if (entry.second.usedKB > entry.second.quotaKB) - { - LOGERR("Application storage usage exceeded allocation: %s (Allocated: %u KB, Used: %u KB)", - entry.second.path.c_str(), entry.second.quotaKB, entry.second.usedKB); - } - else - { - /* quotaKB is total allocated space for the app, and usedKB is the current usage */ - existingAppsReservationSpaceKB += (entry.second.quotaKB - entry.second.usedKB); - } - } - - /* Calculate available space for new apps */ - availableSizeKB = static_cast(curStorageFreeSpaceKB) - static_cast(existingAppsReservationSpaceKB); - - /* Determine if required space is available */ - if (availableSizeKB >= static_cast(requiredSpaceKB)) - { - LOGINFO("Enough space available. Required: %u KB, Available: %llu KB", - requiredSpaceKB, availableSizeKB); - hasEnoughSpace = true; - } - else - { - LOGERR("Not enough space available. Required: %u KB, Available: %llu KB", - requiredSpaceKB, availableSizeKB); - } - } - else - { - LOGERR("Failed to get filesystem stats for path: %s, Error: %s", - baseDir.c_str(), strerror(errno)); - std::lock_guard storageSizelock(mStorageSizeLock); - gStorageSize.blockSize = DEFAULT_STORAGE_DEV_BLOCK_SIZE; /* Fallback to default block size */ - } - } - - return hasEnoughSpace; - } - - /** - * @brief : Creates storage for a given app id and returns the storage path - */ - Core::hresult RequestHandler::CreateStorage(const std::string& appId, const uint32_t& size, std::string& path, std::string& errorReason) - { - Core::hresult status = Core::ERROR_GENERAL; - std::string appDir = ""; - StorageAppInfo storageInfo; - - LOGINFO("Entered CreateStorage Implementation appId: %s", appId.c_str()); - if (appId.empty()) - { - LOGERR("Invalid App ID"); - errorReason = "appId cannot be empty"; - } - else - { - std::unique_lock lock(mStorageManagerImplLock); - - /* Check if the storage mount directory exists or can be created */ - if (mkdir(mBaseStoragePath.c_str(), STORAGE_DIR_PERMISSION) != 0) - { - /* Check if the error is not directory already exists */ - if (errno != EEXIST) - { - errorReason = "Failed to create base storage directory: " + mBaseStoragePath; - LOGERR("Error creating base storage directory %s", mBaseStoragePath.c_str()); - goto ret_fail; - } - } - - /* Check if the appId storageInfo already exists or can be created */ - if (retrieveAppStorageInfoByAppID(appId, storageInfo)) - { - errorReason = ""; - if (storageInfo.quotaKB == size) - { - /* App storage already exist, no need of map entry update */ - path = storageInfo.path; - status = Core::ERROR_NONE; - goto ret_success; - } - else - { - /* App storage quote size is different now, remove the existing map entry and new entry can be created */ - if (!removeAppStorageInfoByAppID(appId)) - { - LOGERR("Failed to remove storage appId: %s", appId.c_str()); - errorReason = "Failed to remove storage for appId: " + appId; - path = ""; - goto ret_fail; - } - } - } - - if (!hasEnoughStorageFreeSpace(mBaseStoragePath, size)) - { - LOGERR("Insufficient storage space for app [%s]. Requested: %u KB", appId.c_str(), size); - errorReason = "Insufficient storage space"; - goto ret_fail; - } - else - { - /* Check if the app storage directory exists or can be created */ - appDir = mBaseStoragePath + "/" + appId; - - if (mkdir(appDir.c_str(), STORAGE_DIR_PERMISSION) != 0) - { - /* Check if the error is not directory already exists */ - if (errno != EEXIST) - { - errorReason = "Failed to create app storage directory: " + appDir; - LOGERR("Error creating app storage directory %s", appDir.c_str()); - goto ret_fail; - } - } - - /* Create app storage info and add it to the map */ - storageInfo.path = appDir; - storageInfo.uid = -1; /* Will be updated by GetStorage API */ - storageInfo.gid = -1; /* Will be updated by GetStorage API */ - storageInfo.quotaKB = size; - storageInfo.usedKB = 0; /* Initially, no space is used */ - if (createAppStorageInfoByAppID(appId, storageInfo)) - { - LOGINFO("Created storage at appDir: %s", appDir.c_str()); - path = std::move(appDir); - } - else - { - LOGERR("Failed to create storage for appId: %s", appDir.c_str()); - errorReason = "Failed to create storage for appId: " + appId; - path = ""; - } - - //set Quota size in to the persistent store - status = appQuotaSizeProperty(SET, appId, &storageInfo.quotaKB); - if (Core::ERROR_NONE != status) - { - LOGERR("appQuotaSizeProperty Failed to SET for appId[%s]!!!", appId.c_str()); - } - else - { - LOGINFO("appQuotaSizeProperty: SET success for appId[%s]\n", appId.c_str()); - } - - } - } - - ret_success: - ret_fail: - return status; - } - - /** - * @brief : Returns the storage information and location for a given app id - */ - Core::hresult RequestHandler::GetStorage(const string& appId, const int32_t& userId, const int32_t& groupId, string& path, uint32_t& size, uint32_t& used) - { - Core::hresult status = Core::ERROR_GENERAL; - StorageAppInfo storageInfo; - - std::unique_lock lock(mStorageManagerImplLock); - LOGINFO("Entered GetStorage Implementation"); - if(retrieveAppStorageInfoByAppID(appId, storageInfo)) - { - path = storageInfo.path; - size = storageInfo.quotaKB; - used = storageInfo.usedKB; - if (storageInfo.usedKB > storageInfo.quotaKB) - { - LOGWARN("Application storage usage exceeded allocation: %s (Allocated: %u KB, Used: %u KB)",storageInfo.path.c_str(), storageInfo.quotaKB, storageInfo.usedKB); - } - LOGINFO("GetStorage Information path = %s, userId = %d, groupId = %d, size = %u, used = %u ",path.c_str(), userId, groupId, size, used); - - status = Core::ERROR_NONE; - if(storageInfo.uid != userId || storageInfo.gid != groupId) - { - LOGINFO("Stored uid = %d gid = %d are different from param",storageInfo.uid, storageInfo.gid); - if (chown(path.c_str(), userId, groupId) != 0) - { - LOGERR("Failed to set ownership: %s", strerror(errno)); - status = Core::ERROR_GENERAL; - } - else - { - storageInfo.uid = userId; - storageInfo.gid = groupId; - /* update uid and gid */ - if (!createAppStorageInfoByAppID(appId, storageInfo)) - { - LOGERR("Failed to update uid and gid of App storageInfo"); - status = Core::ERROR_GENERAL; - } - } - } - } - else - { - LOGERR("Failed to get the Information of the appId: %s", appId.c_str()); - } - return status; - } - - /** - * @brief : Deletes storage for a given app id - */ - Core::hresult RequestHandler::DeleteStorage(const string& appId, string& errorReason) - { - Core::hresult status = Core::ERROR_GENERAL; - LOGINFO("Entered DeleteStorage Implementation"); - - if (appId.empty()) - { - errorReason = "AppId is empty"; - LOGERR("AppId is empty"); - } - else - { - /* Lock the map to ensure thread safety */ - std::unique_lock lock(mStorageManagerImplLock); - /* Check if the App Folder exists in the map */ - auto it = mStorageAppInfo.find(appId); - if (it == mStorageAppInfo.end()) - { - errorReason = "AppId not found in storage info"; - LOGERR("AppId not found in storage info"); - } - else - { - const std::string path = it->second.path; - LOGINFO("App Folder exists, attempting to delete: %s", path.c_str()); - if (deleteDirectoryEntries(appId, errorReason) == Core::ERROR_NONE) - { - if (0 == rmdir(path.c_str())) - { - LOGINFO("App Folder removed successfully"); - status = Core::ERROR_NONE; - LOGINFO("Erasing the App Folder from the database"); - mStorageAppInfo.erase(it); - appQuotaSizeProperty(DELETE, appId, nullptr); //Remove the persistent store entry. - } - else - { - errorReason = "Error deleting the empty App Folder: " + std::string(strerror(errno)); - LOGERR("Error deleting the empty App Folder: reason=%s, Path: %s", strerror(errno), path.c_str()); - } - } - } - } - return status; - } - - /** - * @brief : Callback function used by nftw to delete files and directories - * - * Deletes files and symbolic links using unlink - * and directories using rmdir - */ - int deleteCallback(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) - { - int status = 0; - - if (ftwbuf->level == 0) - { - LOGINFO("Skip deleting root directory: %s", path); - } - else - { - switch (typeflag) - { - case FTW_DP: - if (rmdir(path) != 0) - { - LOGERR("Failed to delete directory: %s, Error: %s", path, strerror(errno)); - status = -1; - } - break; - - case FTW_F: - case FTW_SL: - if (unlink(path) != 0) - { - LOGERR("Failed to delete file: %s, Error: %s", path, strerror(errno)); - status = -1; - } - break; - - default: - LOGERR("Unhandled type: %d for path: %s", typeflag, path); - status = -1; - break; - } - } - return status; - } - - /** - * @brief : Deletes all entries within the specified directory - */ - Core::hresult RequestHandler::deleteDirectoryEntries(const string& appId, string& errorReason) - { - Core::hresult status = Core::ERROR_GENERAL; - std::unique_lock appLock; - - if (!lockAppStorageInfo(appId, appLock)) - { - errorReason = "Storage not found for appId: " + appId; - } - else - { - auto it = mStorageAppInfo.find(appId); - if(it != mStorageAppInfo.end()) - { - const std::string path = it->second.path; - LOGINFO("Clearing App storage path: %s", path.c_str()); - if (nftw(path.c_str(), deleteCallback, MAX_NUM_OF_FILE_DESCRIPTORS, FTW_DEPTH | FTW_PHYS) != 0) - { - LOGERR("Failed to clear App storage path: %s",path.c_str()); - errorReason = "Failed to clear App storage path: " + path; - } - else - { - /* Successfully cleared app storage path */ - it->second.usedKB = 0; - errorReason = ""; - status = Core::ERROR_NONE; - } - } - } - return status; - } - - /** - * @brief Locks the storage information for a specific application. - * - * This function searches for the application ID in the mStorageAppInfo map. - * If found, it acquires a lock on the associated storage mutex to ensure - * thread-safe access to the application's storage information. - */ - bool RequestHandler::lockAppStorageInfo(const std::string& appId, std::unique_lock& appLock) - { - bool status = false; - - LOGINFO("lockAppStorageInfo"); - - auto it = mStorageAppInfo.find(appId); - if (it == mStorageAppInfo.end()) - { - LOGERR("App ID %s not found in storage info", appId.c_str()); - } - else - { - appLock = std::unique_lock(it->second.storageLock); - status = true; - } - return status; - } - - /** - * @brief : Clears storage for a given app id - */ - Core::hresult RequestHandler::Clear(const string& appId, string& errorReason) - { - Core::hresult status = Core::ERROR_GENERAL; - LOGINFO("Entered Clear Implementation"); - std::unique_lock lock(mStorageManagerImplLock); - - if (appId.empty()) - { - errorReason = "Clear called with no appId"; - } - else - { - status = deleteDirectoryEntries(appId, errorReason); - } - return status; - } - - /** - * @brief : Clears all app data except for the exempt app ids - */ - Core::hresult RequestHandler::ClearAll(const string& exemptionAppIds, string& errorReason) - { - Core::hresult status = Core::ERROR_GENERAL; - JsonValue parameters; - LOGINFO("Entered ClearAll Implementation"); - std::unique_lock lock(mStorageManagerImplLock); - - parameters.FromString(exemptionAppIds); - std::list exemptedIdsStrList; - if (parameters.Content()== JsonValue::type::ARRAY) - { - const JsonArray exemptedIdsjson = parameters.Array(); - for (unsigned int i = 0; i < exemptedIdsjson.Length(); i++) - { - exemptedIdsStrList.push_back(exemptedIdsjson[i].String()); - } - } - else - { - LOGERR("invalid exemptionappids format. input is not in array format"); - } - DIR* dir = opendir(mBaseStoragePath.c_str()); - if (!dir) - { - errorReason = "Failed to open storage directory: " + mBaseStoragePath; - } - else - { - bool deletionFailed = false; - struct dirent* entry; - while ((entry = readdir(dir)) != nullptr) - { - if (entry->d_type != DT_DIR || strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - { - continue; - } - - string appDirName = entry->d_name; - if (std::find(exemptedIdsStrList.begin(), exemptedIdsStrList.end(), appDirName) != exemptedIdsStrList.end()) - { - LOGINFO("Skipping exempted app directory: %s", appDirName.c_str()); - continue; - } - - Core::hresult deleteStatus = deleteDirectoryEntries(appDirName, errorReason); - if (deleteStatus != Core::ERROR_NONE) - { - LOGERR("Error deleting directory entries for: %s", appDirName.c_str()); - deletionFailed = true; - } - } - closedir(dir); - - if (!deletionFailed) - { - status = Core::ERROR_NONE; - } - } - return status; - } - /** - * @brief : Set the BaseStoragePath - * - * @param[in] path : Base storage path - */ - void RequestHandler::SetBaseStoragePath(const std::string& path) - { - mBaseStoragePath = path; - LOGINFO("Base Storage Path Set: %s", mBaseStoragePath.c_str()); - } - } -} diff --git a/StorageManager/RequestHandler.h b/StorageManager/RequestHandler.h deleted file mode 100755 index 1d570a1..0000000 --- a/StorageManager/RequestHandler.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include "Module.h" -#include -#include -#include - -namespace WPEFramework -{ - namespace Plugin - { - class RequestHandler - { - public: - static RequestHandler& getInstance(); - RequestHandler(const RequestHandler&) = delete; - RequestHandler& operator=(const RequestHandler&) = delete; - ~RequestHandler(); - - void SetBaseStoragePath(const std::string& path); - typedef struct _StorageAppInfo - { - std::string path; /* Path to the application's storage */ - int32_t uid; /* UID of the user who owns the storage */ - int32_t gid; /* GID of the group who owns the storage */ - uint32_t quotaKB; /* Quota size in kilobytes for the storage */ - uint32_t usedKB; /* Used space in kilobytes for the storage */ - std::mutex storageLock; /* Mutex for thread safety */ - } StorageAppInfo; - - typedef struct _StorageSize - { - uint64_t blockSize = 0; - uint64_t usedBytes = 0; - } StorageSize; - - enum StorageActionType - { - UNKNOWN = 0, - SET, - GET, - DELETE - }; - - bool isValidAppStorageDirectory(const std::string& dirName); - Core::hresult createPersistentStoreRemoteStoreObject(); - void releasePersistentStoreRemoteStoreObject(); - Core::hresult appQuotaSizeProperty(StorageActionType actionType, const std::string& appId, uint32_t* quotaValue); - Core::hresult populateAppInfoCacheFromStoragePath(); - void setCurrentService(PluginHost::IShell* service); - - Core::hresult CreateStorage(const string& appId, const uint32_t& size, string& path, string& errorReason); - Core::hresult GetStorage(const string& appId, const int32_t& userId, const int32_t& groupId, string& path, uint32_t& size, uint32_t& used); - Core::hresult DeleteStorage(const string& appId, string& errorReason); - Core::hresult Clear(const string& appId, string& errorReason); - Core::hresult ClearAll(const string& exemptionAppIds, string& errorReason); - - private: - - bool createAppStorageInfoByAppID(const std::string& appId, StorageAppInfo &storageInfo); - bool retrieveAppStorageInfoByAppID(const string &appId, StorageAppInfo &storageInfo); - bool removeAppStorageInfoByAppID(const string &appId); - bool hasEnoughStorageFreeSpace(const std::string& baseDir, uint32_t requiredSpaceKB); - uint64_t getDirectorySizeInBytes(const std::string &path); - static int getSize(const char *path, const struct stat *statPtr, int currentFlag, struct FTW *internalFtwUsage); - Core::hresult deleteDirectoryEntries(const string& appId, string& errorReason); - bool lockAppStorageInfo(const std::string& appId, std::unique_lock& appLock); - - /*Members*/ - RequestHandler(); - PluginHost::IShell* mService; - static RequestHandler* mInstance; - mutable std::mutex mStorageManagerImplLock; - static std::mutex mStorageSizeLock; - Exchange::IStore2* mPersistentStoreRemoteStoreObject; - std::map mStorageAppInfo; /* Map storing app storage info for each appId */ - std::string mBaseStoragePath; - }; - } /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/StorageManager/StorageManager.conf.in b/StorageManager/StorageManager.conf.in deleted file mode 100755 index f2a3d6a..0000000 --- a/StorageManager/StorageManager.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.StorageManager" -autostart = "@PLUGIN_STORAGE_MANAGER_AUTOSTART@" -startuporder = "@PLUGIN_STORAGE_MANAGER_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_STORAGE_MANAGER_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) -configuration.add("path", "@PLUGIN_STORAGE_MANAGER_PATH@") \ No newline at end of file diff --git a/StorageManager/StorageManager.config b/StorageManager/StorageManager.config deleted file mode 100755 index 3ff0b85..0000000 --- a/StorageManager/StorageManager.config +++ /dev/null @@ -1,17 +0,0 @@ -set (autostart ${PLUGIN_STORAGE_MANAGER_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.StorageManager") - -if(PLUGIN_STORAGE_MANAGER_STARTUPORDER) -set (startuporder ${PLUGIN_STORAGE_MANAGER_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_STORAGE_MANAGER_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() - kv(path ${PLUGIN_STORAGE_MANAGER_PATH}) -end() -ans(configuration) \ No newline at end of file diff --git a/StorageManager/StorageManager.cpp b/StorageManager/StorageManager.cpp deleted file mode 100755 index 430183a..0000000 --- a/StorageManager/StorageManager.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -#include "StorageManager.h" - -const string WPEFramework::Plugin::StorageManager::SERVICE_NAME = "org.rdk.StorageManager"; - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - STORAGE_MANAGER_API_VERSION_NUMBER_MAJOR, STORAGE_MANAGER_API_VERSION_NUMBER_MINOR, STORAGE_MANAGER_API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register StorageManager module as wpeframework plugin - **/ - SERVICE_REGISTRATION(StorageManager, STORAGE_MANAGER_API_VERSION_NUMBER_MAJOR, STORAGE_MANAGER_API_VERSION_NUMBER_MINOR, STORAGE_MANAGER_API_VERSION_NUMBER_PATCH); - - StorageManager::StorageManager() : - mCurrentService(nullptr), - mConnectionId(0), - mStorageManagerImpl(nullptr), - mConfigure(nullptr) - { - SYSLOG(Logging::Startup, (_T("StorageManager Constructor"))); - } - - StorageManager::~StorageManager() - { - SYSLOG(Logging::Shutdown, (string(_T("StorageManager Destructor")))); - } - - const string StorageManager::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mStorageManagerImpl); - ASSERT(0 == mConnectionId); - - SYSLOG(Logging::Startup, (_T("StorageManager::Initialize: PID=%u"), getpid())); - mCurrentService = service; - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - if (nullptr == (mStorageManagerImpl = mCurrentService->Root(mConnectionId, 5000, _T("StorageManagerImplementation")))) - { - SYSLOG(Logging::Startup, (_T("StorageManager::Initialize: object creation failed"))); - message = _T("StorageManager plugin could not be initialised"); - } - else - { - mConfigure = mStorageManagerImpl->QueryInterface(); - if (mConfigure != nullptr) - { - uint32_t result = mConfigure->Configure(mCurrentService); - if(result != Core::ERROR_NONE) - { - message = _T("mStorageManagerImpl could not be configured"); - } - } - else - { - message = _T("mStorageManagerImpl implementation did not provide a configuration interface"); - } - // Invoking Plugin API register to wpeframework - Exchange::JStorageManager::Register(*this, mStorageManagerImpl); - } - } - else - { - SYSLOG(Logging::Startup, (_T("StorageManager::Initialize: service is not valid"))); - message = _T("StorageManager plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void StorageManager::Deinitialize(PluginHost::IShell* service) - { - ASSERT(mCurrentService == service); - - SYSLOG(Logging::Shutdown, (string(_T("StorageManager::Deinitialize")))); - - if (mConfigure != nullptr) - { - mConfigure->Release(); - mConfigure = nullptr; - } - if (nullptr != mStorageManagerImpl) - { - Exchange::JStorageManager::Unregister(*this); - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - VARIABLE_IS_NOT_USED uint32_t result = mStorageManagerImpl->Release(); - - mStorageManagerImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mCurrentService->Release(); - mCurrentService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("StorageManager de-initialised")))); - } - - string StorageManager::Information() const - { - // No additional info to report - return (string()); - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/StorageManager/StorageManager.h b/StorageManager/StorageManager.h deleted file mode 100755 index 3cdce55..0000000 --- a/StorageManager/StorageManager.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class StorageManager: public PluginHost::IPlugin, public PluginHost::JSONRPC - { - public: - StorageManager(const StorageManager&) = delete; - StorageManager& operator=(const StorageManager&) = delete; - - StorageManager(); - virtual ~StorageManager(); - - BEGIN_INTERFACE_MAP(StorageManager) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IStorageManager, mStorageManagerImpl) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - PluginHost::IShell* mCurrentService{}; - uint32_t mConnectionId{}; - Exchange::IStorageManager* mStorageManagerImpl{}; - Exchange::IConfiguration* mConfigure{}; - - public /* constants */: - static const string SERVICE_NAME; - - }; - -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/StorageManager/StorageManagerImplementation.cpp b/StorageManager/StorageManagerImplementation.cpp deleted file mode 100755 index c0b1b85..0000000 --- a/StorageManager/StorageManagerImplementation.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -#include "StorageManagerImplementation.h" -#include "UtilsLogging.h" -#include "RequestHandler.h" -#include - -#define DEFAULT_APP_STORAGE_PATH "/opt/persistent/storageManager" - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#endif - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(StorageManagerImplementation, 1, 0); - - StorageManagerImplementation::StorageManagerImplementation() - : mCurrentservice(nullptr) -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - , mTelemetryMetricsObject(nullptr) -#endif - { - LOGINFO("Create StorageManagerImplementation Instance"); - } - - StorageManagerImplementation::~StorageManagerImplementation() - { - LOGINFO("Delete StorageManagerImplementation Instance"); - RequestHandler& handler = RequestHandler::getInstance(); - handler.releasePersistentStoreRemoteStoreObject(); - - if (nullptr != mCurrentservice) - { - mCurrentservice->Release(); - mCurrentservice = nullptr; - } - } - - uint32_t StorageManagerImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_NONE; - Core::hresult status = Core::ERROR_GENERAL; - - if (service != nullptr) - { - mCurrentservice = service; - if (nullptr != mCurrentservice) - { - mCurrentservice->AddRef(); - - auto configLine = mCurrentservice->ConfigLine(); - - _config.FromString(configLine); - mBaseStoragePath = _config.Path.Value(); - RequestHandler& handler = RequestHandler::getInstance(); - if (mBaseStoragePath.empty()) - { - LOGWARN("Base storage path is empty. Setting default path: %s", DEFAULT_APP_STORAGE_PATH); - mBaseStoragePath = DEFAULT_APP_STORAGE_PATH; // Fallback path - } - - handler.setCurrentService(mCurrentservice); - if (Core::ERROR_NONE != handler.createPersistentStoreRemoteStoreObject()) - { - LOGERR("Failed to create createPersistentStoreRemoteStoreObject"); - } - else - { - LOGINFO("created createPersistentStoreRemoteStoreObject"); - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - if (nullptr == (mTelemetryMetricsObject = mCurrentservice->QueryInterfaceByCallsign("org.rdk.TelemetryMetrics"))) - { - LOGERR("mTelemetryMetricsObject is null \n"); - } - else - { - LOGINFO("created TelemetryMetrics Object"); - } -#endif - - Core::SystemInfo::SetEnvironment(PATH_ENV, mBaseStoragePath.c_str()); - LOGINFO("Base Storage Path Set: %s", mBaseStoragePath.c_str()); - handler.SetBaseStoragePath(mBaseStoragePath); - status = handler.populateAppInfoCacheFromStoragePath(); - if (Core::ERROR_NONE != status) - { - LOGERR("populateAppInfoCacheFromStoragePath Failed!!!"); - } - else - { - LOGINFO("populateAppInfoCacheFromStoragePath Success!!"); - } - } - } - else - { - LOGERR("service is null \n"); - result = Core::ERROR_GENERAL; - } - - return result; - } - -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - static time_t getCurrentTimestamp() - { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((time_t)ts.tv_sec * 1000) + ((time_t)ts.tv_nsec/1000000)); - } -#endif - - /** - * @brief : Creates storage for a given app id and returns the storage path - */ - Core::hresult StorageManagerImplementation::CreateStorage(const std::string& appId, const uint32_t& size, std::string& path, std::string& errorReason) - { - LOGINFO("Entered CreateStorage Implementation appId: %s", appId.c_str()); - Core::hresult status = Core::ERROR_GENERAL; - RequestHandler& handler = RequestHandler::getInstance(); - if (appId.empty()) - { - LOGERR("Invalid App ID"); - errorReason = "appId cannot be empty"; - } - else if (Core::ERROR_NONE != (status = handler.CreateStorage(appId, size, path, errorReason))) - { - LOGERR("Failed to create storage for appId: %s, status %u, Error: %s", appId.c_str(), status, errorReason.c_str()); - } - else - { - LOGINFO("Storage created successfully for appId: %s", appId.c_str()); - } - return status; - } - - /** - * @brief : Returns the storage information and location for a given app id - */ - Core::hresult StorageManagerImplementation::GetStorage(const string& appId, const int32_t& userId, const int32_t& groupId, string& path, uint32_t& size, uint32_t& used) - { - LOGINFO("Entered GetStorage Implementation"); - Core::hresult status = Core::ERROR_GENERAL; - RequestHandler& handler = RequestHandler::getInstance(); - - #ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - JsonObject jsonParam; - std::string telemetryMetrics = ""; - /* Get current timestamp at the start of getStorage for telemetry */ - time_t requestTime = getCurrentTimestamp(); - #endif - - if (appId.empty()) - { - LOGERR("Invalid App ID"); - } - else if (Core::ERROR_NONE != (status = handler.GetStorage(appId, userId, groupId, path, size, used))) - { - LOGERR("Failed to get storage information for appId: %s status %u", appId.c_str(), status); - } - else - { - LOGINFO("Storage retreived successfully for appId: %s", appId.c_str()); - } - - #ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - /* Get current timestamp at the end of getStorage for Telemetry */ - time_t currentTime = getCurrentTimestamp(); - int duration = static_cast(currentTime - requestTime); - jsonParam["storageManagerLaunchTime"] = duration; - jsonParam["appId"] = appId; - jsonParam.ToString(telemetryMetrics); - if(nullptr != mTelemetryMetricsObject) - { - LOGINFO("Record appId %s storageManagerLaunchTime %d",appId.c_str(),duration); - mTelemetryMetricsObject->Record(appId, telemetryMetrics, TELEMETRY_MARKER_LAUNCH_TIME); - } - #endif - return status; - } - - /** - * @brief : Deletes storage for a given app id - */ - Core::hresult StorageManagerImplementation::DeleteStorage(const string& appId, string& errorReason) - { - LOGINFO("Entered DeleteStorage Implementation"); - Core::hresult status = Core::ERROR_GENERAL; - RequestHandler& handler = RequestHandler::getInstance(); - if (appId.empty()) - { - errorReason = "AppId is empty"; - LOGERR("AppId is empty"); - } - else if (Core::ERROR_NONE != (status = handler.DeleteStorage(appId, errorReason))) - { - LOGERR("Failed to delete storage for appId: %s, status %u,Error: %s", appId.c_str(), status, errorReason.c_str()); - } - else - { - LOGINFO("Storage deleted successfully for appId: %s", appId.c_str()); - } - return status; - } - - /** - * @brief : Clears storage for a given app id - */ - Core::hresult StorageManagerImplementation::Clear(const string& appId, string& errorReason) - { - LOGINFO("Entered Clear Implementation"); - Core::hresult status = Core::ERROR_GENERAL; - RequestHandler& handler = RequestHandler::getInstance(); - - if(appId.empty()) - { - errorReason = "Clear called with no appId"; - LOGERR("Clear called with no appId"); - } - else if(Core::ERROR_NONE != (status = handler.Clear(appId, errorReason))) - { - LOGERR("Failed to clear storage for appId: %s, status %u, Error: %s", appId.c_str(), status, errorReason.c_str()); - } - else - { - LOGINFO("Cleared storage successfully for appId: %s", appId.c_str()); - } - return status; - } - - /** - * @brief : Clears all app data except for the exempt app ids - */ - Core::hresult StorageManagerImplementation::ClearAll(const string& exemptionAppIds, string& errorReason) - { - LOGINFO("Entered ClearAll Implementation"); - Core::hresult status = Core::ERROR_GENERAL; - JsonObject parameters; - RequestHandler& handler = RequestHandler::getInstance(); - - if (Core::ERROR_NONE != (status = handler.ClearAll(exemptionAppIds, errorReason))) - { - LOGERR("Failed to clear all storage status %u, Error: %s", status, errorReason.c_str()); - } - else - { - LOGINFO("Cleared all storage successfully, except for exempted app ids %s", exemptionAppIds.c_str()); - } - return status; - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/StorageManager/StorageManagerImplementation.h b/StorageManager/StorageManagerImplementation.h deleted file mode 100755 index 746b648..0000000 --- a/StorageManager/StorageManagerImplementation.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS -#include -#endif -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class StorageManagerImplementation : public Exchange::IStorageManager ,public Exchange::IConfiguration{ - - private: - class Config : public Core::JSON::Container { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - - public: - Config() - : Core::JSON::Container() - { - Add(_T("path"), &Path); - } - - public: - Core::JSON::String Path; - }; - - public: - - StorageManagerImplementation(); - ~StorageManagerImplementation() override; - - StorageManagerImplementation(const StorageManagerImplementation&) = delete; - StorageManagerImplementation& operator=(const StorageManagerImplementation&) = delete; - - BEGIN_INTERFACE_MAP(StorageManagerImplementation) - INTERFACE_ENTRY(Exchange::IStorageManager) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - Core::hresult CreateStorage(const string& appId, const uint32_t& size, string& path, string& errorReason) override; - Core::hresult GetStorage(const string& appId, const int32_t& userId, const int32_t& groupId, string& path, uint32_t& size, uint32_t& used) override; - Core::hresult DeleteStorage(const string& appId, string& errorReason) override; - Core::hresult Clear(const string& appId, string& errorReason) override; - Core::hresult ClearAll(const string& exemptionAppIds, string& errorReason) override; - - // IConfiguration methods - uint32_t Configure(PluginHost::IShell* service) override; - - private: - - Config _config; - PluginHost::IShell* mCurrentservice; -#ifdef ENABLE_AIMANAGERS_TELEMETRY_METRICS - Exchange::ITelemetryMetrics* mTelemetryMetricsObject; -#endif - std::string mBaseStoragePath; /* Base path for the app storage */ - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/Telemetry/CHANGELOG.md b/Telemetry/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/Telemetry/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/Telemetry/CMakeLists.txt b/Telemetry/CMakeLists.txt deleted file mode 100644 index 404b49c..0000000 --- a/Telemetry/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME Telemetry) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_TELEMETRY_STARTUPORDER "" CACHE STRING "To configure startup order of Telemetry plugin") -set(PLUGIN_T2_PERSISTENT_FOLDER /opt/.t2reportprofiles/ CACHE STRING "Path to t2 persistent folder") -set(PLUGIN_DEFAULT_PROFILES_FILE /etc/t2profiles/default.json CACHE STRING "Path to default t2 profile") - -find_package(${NAMESPACE}Plugins REQUIRED) - -add_library(${MODULE_NAME} SHARED - Telemetry.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -include_directories( - ../helpers) - -target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - TelemetryImplementation.cpp - Module.cpp) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST) - -list(APPEND CMAKE_MODULE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") - -find_package(RFC) - -find_path(RBUS_API_HEADER NAMES rbus.h PATH_SUFFIXES rbus) - -if (NOT ${RBUS_API_HEADER} STREQUAL "RBUS_API_HEADER-NOTFOUND") - message("Found rbus.h ${RBUS_API_HEADER}") - add_definitions (-DHAS_RBUS) - set(RBUS_API_HEADERS ${RBUS_API_HEADER}) -find_library(RBUS_LIBRARY NAMES rbus) -endif() - -set(RBUS_LIBRARIES "") -if (NOT ${RBUS_LIBRARY} STREQUAL "RBUS_LIBRARY-NOTFOUND") - set(RBUS_LIBRARIES ${RBUS_LIBRARY}) -endif() - -find_package(IARMBus) - -set(SEC_UTIL_LIBRARIES "") -find_library(SEC_UTIL_LIB NAMES WPEFrameworkSecurityUtil) -if (NOT ${SEC_UTIL_LIB} STREQUAL "SEC_UTIL_LIB-NOTFOUND") - set(SEC_UTIL_LIBRARIES ${SEC_UTIL_LIB}) -endif() - -target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${RFC_INCLUDE_DIRS} ${RBUS_API_HEADERS} ../helpers) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${RFC_LIBRARIES} ${RBUS_LIBRARIES} ${SEC_UTIL_LIBRARIES}) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/Telemetry/Module.cpp b/Telemetry/Module.cpp deleted file mode 100644 index ce759b6..0000000 --- a/Telemetry/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/Telemetry/Module.h b/Telemetry/Module.h deleted file mode 100644 index 567c134..0000000 --- a/Telemetry/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Telemetry -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/Telemetry/README.md b/Telemetry/README.md deleted file mode 100644 index 60c427e..0000000 --- a/Telemetry/README.md +++ /dev/null @@ -1,17 +0,0 @@ ------------------ -Build: - -bitbake wpeframework-service-plugins - ------------------ -Test: - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.Telemetry.1.getAvailableReportProfiles"}' http://127.0.0.1:9998/jsonrpc - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.Telemetry.1.setReportProfileStatus", "params" : {"reportProfile" : "FTUE", "status" : "STARTED" }}' http://127.0.0.1:9998/jsonrpc - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.Telemetry.1.setReportProfileStatus", "params" : {"reportProfile" : "FTUE", "status" : "COMPLETE" }}' http://127.0.0.1:9998/jsonrpc - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.Telemetry.1.logApplicationEvent", "params" : {"eventName" : "event", "eventValue" : "value" }}' http://127.0.0.1:9998/jsonrpc - -curl --header "Content-Type: application/json" --request POST --data '{"jsonrpc":"2.0","id":"3","method": "org.rdk.Telemetry.1.uploadReport"}' http://127.0.0.1:9998/jsonrpc diff --git a/Telemetry/Telemetry.conf.in b/Telemetry/Telemetry.conf.in deleted file mode 100644 index 53855b3..0000000 --- a/Telemetry/Telemetry.conf.in +++ /dev/null @@ -1,14 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.Telemetry" -autostart = "false" -startuporder = "@PLUGIN_TELEMETRY_STARTUPORDER@" - -configuration = JSON() -rootobject = JSON() - -rootobject.add("mode", "@PLUGIN_TELEMETRY_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") - -configuration.add("root", rootobject) -configuration.add("t2PersistentFolder", "@PLUGIN_T2_PERSISTENT_FOLDER@") -configuration.add("defaultProfilesFile", "@PLUGIN_DEFAULT_PROFILES_FILE@") diff --git a/Telemetry/Telemetry.config b/Telemetry/Telemetry.config deleted file mode 100644 index db4fc39..0000000 --- a/Telemetry/Telemetry.config +++ /dev/null @@ -1,18 +0,0 @@ -set (autostart false) -set (preconditions Platform) -set (callsign "org.rdk.Telemetry") - -if(PLUGIN_TELEMETRY_STARTUPORDER) -set (startuporder ${PLUGIN_TELEMETRY_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_TELEMETRY_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - kv(t2PersistentFolder ${PLUGIN_T2_PERSISTENT_FOLDER}) - kv(defaultProfilesFile ${PLUGIN_DEFAULT_PROFILES_FILE} ) - end() -end() -ans(configuration) diff --git a/Telemetry/Telemetry.cpp b/Telemetry/Telemetry.cpp deleted file mode 100644 index 492f65b..0000000 --- a/Telemetry/Telemetry.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Telemetry.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 2 -#define API_VERSION_NUMBER_PATCH 2 - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register Telemetry module as wpeframework plugin - **/ - SERVICE_REGISTRATION(Telemetry, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - Telemetry::Telemetry() : _service(nullptr), _connectionId(0), _telemetry(nullptr), _telemetryNotification(this) - { - SYSLOG(Logging::Startup, (_T("Telemetry Constructor"))); - } - - Telemetry::~Telemetry() - { - SYSLOG(Logging::Shutdown, (string(_T("Telemetry Destructor")))); - } - - const string Telemetry::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == _service); - ASSERT(nullptr == _telemetry); - ASSERT(0 == _connectionId); - - SYSLOG(Logging::Startup, (_T("Telemetry::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - _service->Register(&_telemetryNotification); - _telemetry = _service->Root(_connectionId, 5000, _T("TelemetryImplementation")); - - if(nullptr != _telemetry) - { - configure = _telemetry->QueryInterface(); - if (configure != nullptr) - { - uint32_t result = configure->Configure(_service); - if(result != Core::ERROR_NONE) - { - message = _T("Telemetry could not be configured"); - } - } - else - { - message = _T("Telemetry implementation did not provide a configuration interface"); - } - // Register for notifications - _telemetry->Register(&_telemetryNotification); - // Invoking Plugin API register to wpeframework - Exchange::JTelemetry::Register(*this, _telemetry); - } - else - { - SYSLOG(Logging::Startup, (_T("Telemetry::Initialize: Failed to initialise Telemetry plugin"))); - message = _T("Telemetry plugin could not be initialised"); - } - return message; - } - - void Telemetry::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("Telemetry::Deinitialize")))); - - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - _service->Unregister(&_telemetryNotification); - - if (nullptr != _telemetry) - { - - _telemetry->Unregister(&_telemetryNotification); - Exchange::JTelemetry::Unregister(*this); - - if (configure != nullptr) { - configure->Release(); - configure = nullptr; - } - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED uint32_t result = _telemetry->Release(); - - _telemetry = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - try - { - connection->Terminate(); - // Log success if needed - LOGWARN("Connection terminated successfully."); - } - catch (const std::exception& e) - { - std::string errorMessage = "Failed to terminate connection: "; - errorMessage += e.what(); - LOGWARN("%s",errorMessage.c_str()); - } - - connection->Release(); - } - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("Telemetry de-initialised")))); - } - - string Telemetry::Information() const - { - return ("This Telemetry Plugin facilitates to persist event data for monitoring applications"); - } - - void Telemetry::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == _connectionId) { - ASSERT(nullptr != _service); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/Telemetry/Telemetry.h b/Telemetry/Telemetry.h deleted file mode 100644 index ad5227a..0000000 --- a/Telemetry/Telemetry.h +++ /dev/null @@ -1,111 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" - -namespace WPEFramework -{ - namespace Plugin - { - class Telemetry : public PluginHost::IPlugin, public PluginHost::JSONRPC - { - private: - class Notification : public RPC::IRemoteConnection::INotification, public Exchange::ITelemetry::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(Telemetry* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::ITelemetry::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - LOGINFO("Telemetry Notification Activated"); - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - LOGINFO("Telemetry Notification Deactivated"); - _parent.Deactivated(connection); - } - - void OnReportUpload(const string& telemetryUploadStatus ) override - { - LOGINFO("OnReportUpload: telemetryUploadStatus %s\n", telemetryUploadStatus.c_str()); - Exchange::JTelemetry::Event::OnReportUpload(_parent, telemetryUploadStatus); - } - - private: - Telemetry& _parent; - }; - - public: - Telemetry(const Telemetry&) = delete; - Telemetry& operator=(const Telemetry&) = delete; - - Telemetry(); - virtual ~Telemetry(); - - BEGIN_INTERFACE_MAP(Telemetry) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::ITelemetry, _telemetry) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* _service{}; - uint32_t _connectionId{}; - Exchange::ITelemetry* _telemetry{}; - Core::Sink _telemetryNotification; - Exchange::IConfiguration* configure; - }; - } // namespace Plugin -} // namespace WPEFramework diff --git a/Telemetry/TelemetryImplementation.cpp b/Telemetry/TelemetryImplementation.cpp deleted file mode 100644 index 8a4edec..0000000 --- a/Telemetry/TelemetryImplementation.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "TelemetryImplementation.h" - -#include "UtilsJsonRpc.h" -#include "UtilsTelemetry.h" -#include "UtilsController.h" - -#include "rfcapi.h" -#include - -#ifdef HAS_RBUS -#include "rbus.h" - -#define RBUS_COMPONENT_NAME "TelemetryThunderPlugin" -#define T2_ON_DEMAND_REPORT "Device.X_RDKCENTRAL-COM_T2.UploadDCMReport" -#define T2_ABORT_ON_DEMAND_REPORT "Device.X_RDKCENTRAL-COM_T2.AbortDCMReport" -#endif - -#define RFC_CALLERID "Telemetry" -#define RFC_REPORT_PROFILES "Device.X_RDKCENTRAL-COM_T2.ReportProfiles" -#define RFC_REPORT_DEFAULT_PROFILE_ENABLE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Telemetry.FTUEReport.Enable" -#define T2_PERSISTENT_FOLDER "/opt/.t2reportprofiles/" -#define DEFAULT_PROFILES_FILE "/etc/t2profiles/default.json" -#define OPTOUT_TELEMETRY_STATUS "/opt/tmtryoptout" - -#define USERSETTINGS_CALLSIGN "org.rdk.UserSettings" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 2 -#define API_VERSION_NUMBER_PATCH 2 - -#ifdef HAS_RBUS -#define RBUS_PRIVACY_MODE_EVENT_NAME "Device.X_RDKCENTRAL-COM_Privacy.PrivacyMode" - -static rbusError_t rbusHandleStatus = RBUS_ERROR_NOT_INITIALIZED; -static rbusHandle_t rbusHandle; - -#endif -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(TelemetryImplementation, 1, 0); - TelemetryImplementation* TelemetryImplementation::_instance = nullptr; - - TelemetryImplementation::TelemetryImplementation() - : _adminLock() - , _service(nullptr) - , _pwrMgrNotification(*this) -#ifdef HAS_RBUS - , _userSettingsPlugin(nullptr) - , _userSettingsNotification(*this) -#endif - , _registeredEventHandlers(false) - { - LOGINFO("Create TelemetryImplementation Instance"); - TelemetryImplementation::_instance = this; - Utils::Telemetry::init(); - } - - TelemetryImplementation::~TelemetryImplementation() - { - if (_powerManagerPlugin) { - // Unregister from PowerManagerPlugin Notification - _powerManagerPlugin->Unregister(_pwrMgrNotification.baseInterface()); - _powerManagerPlugin.Reset(); - } - - LOGINFO("Call TelemetryImplementation destructor\n"); - _registeredEventHandlers = false; - - TelemetryImplementation::_instance = nullptr; - _service = nullptr; -#ifdef HAS_RBUS - if (RBUS_ERROR_SUCCESS == rbusHandleStatus) { - rbus_close(rbusHandle); - rbusHandleStatus = RBUS_ERROR_NOT_INITIALIZED; - } - - if (_userSettingsPlugin) { - _userSettingsPlugin->Unregister(&_userSettingsNotification); - _userSettingsPlugin->Release(); - _userSettingsPlugin = nullptr; - } -#endif - } - - Core::hresult TelemetryImplementation::Register(Exchange::ITelemetry::INotification *notification) - { - ASSERT (nullptr != notification); - - _adminLock.Lock(); - - // Make sure we can't register the same notification callback multiple times - if (std::find(_telemetryNotification.begin(), _telemetryNotification.end(), notification) == _telemetryNotification.end()) - { - _telemetryNotification.push_back(notification); - notification->AddRef(); - } - else - { - LOGERR("same notification is registered already"); - } - - _adminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult TelemetryImplementation::Unregister(Exchange::ITelemetry::INotification *notification ) - { - Core::hresult status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - _adminLock.Lock(); - - // we just unregister one notification once - auto itr = std::find(_telemetryNotification.begin(), _telemetryNotification.end(), notification); - if (itr != _telemetryNotification.end()) - { - (*itr)->Release(); - _telemetryNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - _adminLock.Unlock(); - - return status; - } - -#ifdef HAS_RBUS - void TelemetryImplementation::getPrivacyMode() - { - ASSERT(_service != nullptr); - - _userSettingsPlugin = _service->QueryInterfaceByCallsign(USERSETTINGS_CALLSIGN); - if (_userSettingsPlugin) - { - _userSettingsPlugin->Register(&_userSettingsNotification); - - std::string privacyMode; - if (_userSettingsPlugin->GetPrivacyMode(privacyMode) == Core::ERROR_NONE) - { - notifyT2PrivacyMode(privacyMode); - } - else - { - LOGERR("Failed to get privacy mode"); - } - } - else - { - LOGERR("Failed to get _userSettingsPlugin handle"); - } - } - - static void t2EventHandler(rbusHandle_t handle, char const* methodName, rbusError_t error, rbusObject_t param) - { - LOGINFO("Got %s rbus callback", methodName); - - if (RBUS_ERROR_SUCCESS == error) - { - rbusValue_t uploadStatus = rbusObject_GetValue(param, "UPLOAD_STATUS"); - - if(uploadStatus) - { - if (TelemetryImplementation::_instance) - TelemetryImplementation::_instance->onReportUploadStatus(rbusValue_GetString(uploadStatus, NULL)); - } - else - { - LOGERR("No 'UPLOAD_STATUS' value"); - if (TelemetryImplementation::_instance) - TelemetryImplementation::_instance->onReportUploadStatus("No 'UPLOAD_STATUS' value"); - } - } - else - { - std::stringstream str; - str << "Call failed with " << error << " error"; - LOGERR("%s", str.str().c_str()); - if (TelemetryImplementation::_instance) - TelemetryImplementation::_instance->onReportUploadStatus(str.str().c_str()); - } - } - - void TelemetryImplementation::onReportUploadStatus(const char* status) - { - JsonObject eventData; - std::string s(status); - eventData["telemetryUploadStatus"] = s == "SUCCESS" ? "UPLOAD_SUCCESS" : "UPLOAD_FAILURE"; - dispatchEvent(TELEMETRY_EVENT_ONREPORTUPLOAD, eventData); - } - - void TelemetryImplementation::notifyT2PrivacyMode(std::string privacyMode) - { - LOGINFO("Privacy mode is %s", privacyMode.c_str()); - if (RBUS_ERROR_SUCCESS != rbusHandleStatus) - { - rbusHandleStatus = rbus_open(&rbusHandle, RBUS_COMPONENT_NAME); - } - - if (RBUS_ERROR_SUCCESS == rbusHandleStatus) - { - rbusValue_t value; - rbusSetOptions_t opts = {true, 0}; - - rbusValue_Init(&value); - rbusValue_SetString(value, privacyMode.c_str()); - int rc = rbus_set(rbusHandle, RBUS_PRIVACY_MODE_EVENT_NAME, value, &opts); - if (rc != RBUS_ERROR_SUCCESS) - { - std::stringstream str; - str << "Failed to set property " << RBUS_PRIVACY_MODE_EVENT_NAME << ": " << rc; - LOGERR("%s", str.str().c_str()); - } - rbusValue_Release(value); - } - else - { - LOGERR("rbus_open failed with error code %d", rbusHandleStatus); - } - } - - static void t2OnAbortEventHandler(rbusHandle_t handle, char const* methodName, rbusError_t error, rbusObject_t param) - { - LOGINFO("Got %s rbus callback", methodName); - } - - -#endif - - void TelemetryImplementation::setRFCReportProfiles() - { - JsonObject config; - config.FromString(_service->ConfigLine()); - std::string t2PersistentFolder = config.HasLabel("t2PersistentFolder") ? config["t2PersistentFolder"].String() : T2_PERSISTENT_FOLDER; - bool isEMpty = true; - DIR *d = opendir(t2PersistentFolder.c_str()); - if (NULL != d) - { - struct dirent *de; - - while ((de = readdir(d))) - { - if (0 == de->d_name[0] || 0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, "..")) - continue; - - isEMpty = false; - break; - } - - closedir(d); - } - - if (isEMpty) - { - Core::File file; - std::string defaultProfilesFile = config.HasLabel("defaultProfilesFile") ? config["defaultProfilesFile"].String() : DEFAULT_PROFILES_FILE; - file = defaultProfilesFile.c_str(); - file.Open(); - if (file.IsOpen()) - { - if (file.Size() > 0) - { - std::vector defaultProfile; - defaultProfile.resize(file.Size() + 1); - uint32_t rs = file.Read((uint8_t *)defaultProfile.data(), file.Size()); - defaultProfile.data()[rs] = 0; - if (file.Size() == rs) - { - - std::stringstream ss; - // Escaping quotes - for (uint32_t n = 0; n < rs; n++) - { - char ch = defaultProfile.data()[n]; - if ('\"' == ch) - ss << "\\"; - ss << ch; - } - - WDMP_STATUS wdmpStatus = setRFCParameter((char *)RFC_CALLERID, RFC_REPORT_PROFILES, ss.str().c_str(), WDMP_STRING); - if (WDMP_SUCCESS != wdmpStatus) - { - LOGERR("Failed to set Device.X_RDKCENTRAL-COM_T2.ReportProfiles: %d", wdmpStatus); - } - } - else - { - LOGERR("Got wrong number of bytes, %d instead of %d", rs, (int)file.Size()); - } - } - else - { - LOGERR("%s is 0 size", defaultProfilesFile.c_str()); - } - } - else - { - LOGERR("Failed to open %s", defaultProfilesFile.c_str()); - } - } - } - uint32_t TelemetryImplementation::Configure(PluginHost::IShell* service) - { - LOGINFO("Configuring TelemetryImplementation"); - uint32_t result = Core::ERROR_NONE; - ASSERT(service != nullptr); - _service = service; - _service->AddRef(); - InitializePowerManager(); - -#ifdef HAS_RBUS - getPrivacyMode(); -#endif - setRFCReportProfiles(); - - return result; - } - - void TelemetryImplementation::InitializePowerManager() - { - LOGINFO("Connect the COM-RPC socket\n"); - _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) - .withIShell(_service) - .withRetryIntervalMS(200) - .withRetryCount(25) - .createInterface(); - - registerEventHandlers(); - } - - - void TelemetryImplementation::registerEventHandlers() - { - ASSERT (_powerManagerPlugin); - - if(!_registeredEventHandlers && _powerManagerPlugin) - { - _registeredEventHandlers = true; - _powerManagerPlugin->Register(_pwrMgrNotification.baseInterface()); - } - } - - void TelemetryImplementation::onPowerModeChanged(const PowerState currentState, const PowerState newState) - { - JsonObject params; - - if (WPEFramework::Exchange::IPowerManager::POWER_STATE_STANDBY == newState || - WPEFramework::Exchange::IPowerManager::POWER_STATE_STANDBY_LIGHT_SLEEP == newState) - { - if (WPEFramework::Exchange::IPowerManager::POWER_STATE_ON == currentState) - { - Core::IWorkerPool::Instance().Submit(Job::Create( this,TELEMETRY_EVENT_UPLOADREPORT, params)); - } - } - else if(WPEFramework::Exchange::IPowerManager::POWER_STATE_STANDBY_DEEP_SLEEP == newState) - { - Core::IWorkerPool::Instance().Submit(Job::Create( this,TELEMETRY_EVENT_ABORTREPORT, params)); - } - } - - void TelemetryImplementation::dispatchEvent(Event event, const JsonValue ¶ms) - { - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, params)); - } - - void TelemetryImplementation::Dispatch(Event event, const JsonValue params) - { - _adminLock.Lock(); - - std::list::const_iterator index(_telemetryNotification.begin()); - - switch(event) - { - case TELEMETRY_EVENT_UPLOADREPORT: - TelemetryImplementation::_instance->UploadReport(); - break; - - case TELEMETRY_EVENT_ABORTREPORT: - TelemetryImplementation::_instance->AbortReport(); - break; - - case TELEMETRY_EVENT_ONREPORTUPLOAD: - while (index != _telemetryNotification.end()) - { - (*index)->OnReportUpload(params.String()); - ++index; - } - break; - - default: - LOGWARN("Event[%u] not handled", event); - break; - } - _adminLock.Unlock(); - } - - Core::hresult TelemetryImplementation::SetReportProfileStatus(const string& status) - { - LOGINFO(); - - if (!status.empty()) - { - if (status != "STARTED" && status != "COMPLETE") - { - LOGERR("Only the 'STARTED' or 'COMPLETE' status is allowed"); - return Core::ERROR_GENERAL; - } - - WDMP_STATUS wdmpStatus = setRFCParameter((char *)RFC_CALLERID, RFC_REPORT_DEFAULT_PROFILE_ENABLE, status == "COMPLETE" ? "true" : "false", WDMP_BOOLEAN); - if (WDMP_SUCCESS != wdmpStatus) - { - LOGERR("Failed to set %s: %d", RFC_REPORT_DEFAULT_PROFILE_ENABLE, wdmpStatus); - return Core::ERROR_GENERAL; - } - return Core::ERROR_NONE; - } - - LOGERR("Empty status' parameter"); - return Core::ERROR_GENERAL; - } - - Core::hresult TelemetryImplementation::LogApplicationEvent(const string& eventName, const string& eventValue) - { - LOGINFO(); - if (eventName.empty() || eventValue.empty()) - { - LOGERR("No 'eventName' or 'eventValue' parameter"); - return Core::ERROR_GENERAL; - } - - LOGINFO("eventName:%s, eventValue:%s", eventName.c_str(), eventValue.c_str()); - Utils::Telemetry::sendMessage((char *)eventName.c_str(), (char *)eventValue.c_str()); - return Core::ERROR_NONE; - } - - Core::hresult TelemetryImplementation::UploadReport() - { - LOGINFO(""); -#ifdef HAS_RBUS - if (RBUS_ERROR_SUCCESS != rbusHandleStatus) - { - rbusHandleStatus = rbus_open(&rbusHandle, RBUS_COMPONENT_NAME); - } - - if (RBUS_ERROR_SUCCESS == rbusHandleStatus) - { - int rc = rbusMethod_InvokeAsync(rbusHandle, T2_ON_DEMAND_REPORT, NULL, t2EventHandler, 0); - if (RBUS_ERROR_SUCCESS != rc) - { - std::stringstream str; - str << "Failed to call " << T2_ON_DEMAND_REPORT << ": " << rc; - LOGERR("%s", str.str().c_str()); - - return Core::ERROR_RPC_CALL_FAILED; - } - } - else - { - std::stringstream str; - str << "rbus_open failed with error code " << rbusHandleStatus; - LOGERR("%s", str.str().c_str()); - return Core::ERROR_OPENING_FAILED; - } -#else - LOGERR("No RBus support"); - return Core::ERROR_NOT_EXIST; -#endif - return Core::ERROR_NONE; - } - - Core::hresult TelemetryImplementation::AbortReport() - { - LOGINFO(""); -#ifdef HAS_RBUS - if (RBUS_ERROR_SUCCESS != rbusHandleStatus) - { - rbusHandleStatus = rbus_open(&rbusHandle, RBUS_COMPONENT_NAME); - } - - if (RBUS_ERROR_SUCCESS == rbusHandleStatus) - { - int rc = rbusMethod_InvokeAsync(rbusHandle, T2_ABORT_ON_DEMAND_REPORT, NULL, t2OnAbortEventHandler, 0); - if (RBUS_ERROR_SUCCESS != rc) - { - std::stringstream str; - str << "Failed to call " << T2_ABORT_ON_DEMAND_REPORT << ": " << rc; - LOGERR("%s", str.str().c_str()); - return Core::ERROR_RPC_CALL_FAILED; - } - } - else - { - std::stringstream str; - str << "rbus_open failed with error code " << rbusHandleStatus; - LOGERR("%s", str.str().c_str()); - return Core::ERROR_OPENING_FAILED; - } -#else - LOGERR("No RBus support"); - return Core::ERROR_NOT_EXIST; -#endif - return Core::ERROR_NONE; - } - - /*** - * @brief : Used to read file contents into a string - * @param1[in] : Complete file name with path - * @param2[out] : Destination string object filled with file contents - * @return : ; TRUE if operation success; else FALSE. - */ - bool TelemetryImplementation::getFileContent(std::string fileName, std::string& fileContent) - { - std::ifstream inFile(fileName.c_str(), ios::in); - if (!inFile.is_open()) return false; - - std::stringstream buffer; - buffer << inFile.rdbuf(); - fileContent = buffer.str(); - inFile.close(); - - return true; - } - - Core::hresult TelemetryImplementation::SetOptOutTelemetry(const bool optOut, TelemetrySuccess& successResult) - { - uint32_t result = Core::ERROR_GENERAL; - ofstream optfile; - optfile.open(OPTOUT_TELEMETRY_STATUS, ios::out); - if (optfile) { - optfile << (optOut ? "true" :"false"); - optfile.close(); - successResult.success = true; - LOGINFO("TelemetryOptOut flag set to %s\n",optOut ? "true" :"false"); - result = Core::ERROR_NONE; - } else { - successResult.success = false; - LOGERR("Couldn't update Telemetry Opt Out flag\n"); - } - return result; - } - - Core::hresult TelemetryImplementation::IsOptOutTelemetry(bool& optOut, bool& success) - { - string optOutStatus; - - bool retVal = getFileContent(OPTOUT_TELEMETRY_STATUS, optOutStatus); - if (retVal && optOutStatus.length()) { - if (optOutStatus.find("true") != string::npos) { - optOut = true; - } else { - optOut = false; - } - } - success = true; - return Core::ERROR_NONE; - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/Telemetry/TelemetryImplementation.h b/Telemetry/TelemetryImplementation.h deleted file mode 100644 index c3139af..0000000 --- a/Telemetry/TelemetryImplementation.h +++ /dev/null @@ -1,214 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include "PowerManagerInterface.h" - -#ifdef HAS_RBUS -#include -#endif - -#include -#include - -using namespace WPEFramework; -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; -using ThermalTemperature = WPEFramework::Exchange::IPowerManager::ThermalTemperature; - -namespace WPEFramework { -namespace Plugin { - class TelemetryImplementation : public Exchange::ITelemetry, public Exchange::IConfiguration - { - private: - class PowerManagerNotification : public Exchange::IPowerManager::IModeChangedNotification { - private: - PowerManagerNotification(const PowerManagerNotification&) = delete; - PowerManagerNotification& operator=(const PowerManagerNotification&) = delete; - - public: - explicit PowerManagerNotification(TelemetryImplementation& parent) - : _parent(parent) - { - } - ~PowerManagerNotification() override = default; - - public: - void OnPowerModeChanged(const PowerState currentState, const PowerState newState) override - { - _parent.onPowerModeChanged(currentState, newState); - } - - template - T* baseInterface() - { - static_assert(std::is_base_of(), "base type mismatch"); - return static_cast(this); - } - - BEGIN_INTERFACE_MAP(PowerManagerNotification) - INTERFACE_ENTRY(Exchange::IPowerManager::IModeChangedNotification) - END_INTERFACE_MAP - - private: - TelemetryImplementation& _parent; - }; - -#ifdef HAS_RBUS - class UserSettingsNotification : public Exchange::IUserSettings::INotification { - private: - UserSettingsNotification(const UserSettingsNotification&) = delete; - UserSettingsNotification& operator=(const UserSettingsNotification&) = delete; - - public: - explicit UserSettingsNotification(TelemetryImplementation& parent) - : _parent(parent) - { - } - - ~UserSettingsNotification() override = default; - - void OnPrivacyModeChanged(const string& privacyMode) - { - _parent.notifyT2PrivacyMode(privacyMode); - } - - BEGIN_INTERFACE_MAP(UserSettingsNotification) - INTERFACE_ENTRY(Exchange::IUserSettings::INotification) - END_INTERFACE_MAP - - private: - TelemetryImplementation& _parent; - }; -#endif - - public: - // We do not allow this plugin to be copied !! - TelemetryImplementation(); - ~TelemetryImplementation() override; - - static TelemetryImplementation* instance(TelemetryImplementation *TelemetryImpl = nullptr); - - // We do not allow this plugin to be copied !! - TelemetryImplementation(const TelemetryImplementation&) = delete; - TelemetryImplementation& operator=(const TelemetryImplementation&) = delete; - - BEGIN_INTERFACE_MAP(TelemetryImplementation) - INTERFACE_ENTRY(Exchange::ITelemetry) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - public: - enum Event - { - TELEMETRY_EVENT_ONREPORTUPLOAD, - TELEMETRY_EVENT_UPLOADREPORT, - TELEMETRY_EVENT_ABORTREPORT - }; - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(TelemetryImplementation* TelemetryImplementation, Event event, JsonValue ¶ms) - : _telemetryImplementation(TelemetryImplementation) - , _event(event) - , _params(params) { - if (_telemetryImplementation != nullptr) { - _telemetryImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (_telemetryImplementation != nullptr) { - _telemetryImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(TelemetryImplementation* telemetryImplementation, Event event, JsonValue params ) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(telemetryImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(telemetryImplementation, event, params))); -#endif - } - - virtual void Dispatch() { - _telemetryImplementation->Dispatch(_event, _params); - } - - private: - TelemetryImplementation *_telemetryImplementation; - const Event _event; - JsonValue _params; - }; - public: - virtual Core::hresult Register(Exchange::ITelemetry::INotification *notification ) override ; - virtual Core::hresult Unregister(Exchange::ITelemetry::INotification *notification ) override; - - Core::hresult SetReportProfileStatus(const string& status) override; - Core::hresult LogApplicationEvent(const string& eventName, const string& eventValue) override; - Core::hresult UploadReport() override; - Core::hresult AbortReport() override; - Core::hresult SetOptOutTelemetry(const bool optOut, TelemetrySuccess& successResult) override; - Core::hresult IsOptOutTelemetry(bool& optOut, bool& success) override; - - void InitializePowerManager(); - void onPowerModeChanged(const PowerState currentState, const PowerState newState); - void registerEventHandlers(); - bool getFileContent(std::string fileName, std::string& fileContent); - - // IConfiguration interface - uint32_t Configure(PluginHost::IShell* service) override; - -#ifdef HAS_RBUS - void notifyT2PrivacyMode(std::string privacyMode); - void onReportUploadStatus(const char* status); - void getPrivacyMode(); - void setRFCReportProfiles(); -#endif - - private: - mutable Core::CriticalSection _adminLock; - PluginHost::IShell* _service; - std::list _telemetryNotification; - PowerManagerInterfaceRef _powerManagerPlugin; - Core::Sink _pwrMgrNotification; -#ifdef HAS_RBUS - Exchange::IUserSettings* _userSettingsPlugin; - Core::Sink _userSettingsNotification; -#endif - bool _registeredEventHandlers; - - void dispatchEvent(Event, const JsonValue ¶ms); - void Dispatch(Event event, const JsonValue params); - public: - static TelemetryImplementation* _instance; - - friend class Job; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/TelemetryMetrics/CMakeLists.txt b/TelemetryMetrics/CMakeLists.txt deleted file mode 100755 index d0f86f0..0000000 --- a/TelemetryMetrics/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2025 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME TelemetryMetrics) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_TELEMETRY_METRICS_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_TELEMETRY_METRICS_AUTOSTART false CACHE STRING "Automatically start TelemetryMetrics plugin") -set(PLUGIN_TELEMETRY_METRICS_EXTRA_LIBRARIES "") -set(PLUGIN_TELEMETRY_METRICS_STARTUPORDER "" CACHE STRING "Automatically start TelemetryMetrics plugin") - -add_definitions(-DTELEMETRY_METRICS_API_VERSION_NUMBER_MAJOR=1) -add_definitions(-DTELEMETRY_METRICS_API_VERSION_NUMBER_MINOR=0) -add_definitions(-DTELEMETRY_METRICS_API_VERSION_NUMBER_PATCH=0) - -set(TELEMETRY_METRICS_IMPLEMENTATION ${PLUGIN_NAME}Implementation) -add_definitions(-DPLUGIN_TELEMETRY_METRICS_IMPLEMENTATION_NAME="${TELEMETRY_METRICS_IMPLEMENTATION}") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - TelemetryMetrics.cpp - Module.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set_source_files_properties(TelemetryMetrics.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - TelemetryMetricsImplementation.cpp - Module.cpp) - -include_directories(../helpers) - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -set(TELEMETRY_METRICS_INCLUDES $ENV{TELEMETRY_METRICS_INCLUDES}) -separate_arguments(TELEMETRY_METRICS_INCLUDES) -include_directories(BEFORE ${TELEMETRY_METRICS_INCLUDES}) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE - CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${PLUGIN_TELEMETRY_METRICS_EXTRA_LIBRARIES}) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/TelemetryMetrics/Module.cpp b/TelemetryMetrics/Module.cpp deleted file mode 100755 index a05f066..0000000 --- a/TelemetryMetrics/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/TelemetryMetrics/Module.h b/TelemetryMetrics/Module.h deleted file mode 100755 index 4a4f0ea..0000000 --- a/TelemetryMetrics/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_TelemetryMetrics -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/TelemetryMetrics/TelemetryFilters.h b/TelemetryMetrics/TelemetryFilters.h deleted file mode 100644 index 47781c4..0000000 --- a/TelemetryMetrics/TelemetryFilters.h +++ /dev/null @@ -1,59 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include - -#define TELEMETRY_MARKER_DOWNLOAD_TIME "DownloadTime_split" -#define TELEMETRY_MARKER_DOWNLOAD_ERROR "DownloadError_split" -#define TELEMETRY_MARKER_INSTALL_TIME "InstallTime_split" -#define TELEMETRY_MARKER_INSTALL_ERROR "InstallError_split" -#define TELEMETRY_MARKER_UNINSTALL_TIME "UninstallTime_split" -#define TELEMETRY_MARKER_UNINSTALL_ERROR "UninstallError_split" -#define TELEMETRY_MARKER_LAUNCH_TIME "OverallLaunchTime_split" -#define TELEMETRY_MARKER_LAUNCH_ERROR "AppLaunchError_split" -#define TELEMETRY_MARKER_CLOSE_TIME "AppCloseTime_split" -#define TELEMETRY_MARKER_CLOSE_ERROR "AppCloseError_split" -#define TELEMETRY_MARKER_SUSPEND_TIME "SuspendTime_split" -#define TELEMETRY_MARKER_RESUME_TIME "ResumeTime_split" -#define TELEMETRY_MARKER_HIBERNATE_TIME "HibernateTime_split" -#define TELEMETRY_MARKER_WAKE_TIME "WakeTime_split" -#define TELEMETRY_MARKER_APP_CRASHED "AppCrashed_split" - - -static const std::unordered_map> markerFilters = { - {TELEMETRY_MARKER_DOWNLOAD_TIME, {"downloadTime", "markerName"}}, - {TELEMETRY_MARKER_DOWNLOAD_ERROR, {"errorCode", "markerName"}}, - {TELEMETRY_MARKER_INSTALL_TIME, {"installTime", "markerName"}}, - {TELEMETRY_MARKER_INSTALL_ERROR, {"errorCode", "markerName"}}, - {TELEMETRY_MARKER_UNINSTALL_TIME, {"uninstallTime", "markerName"}}, - {TELEMETRY_MARKER_UNINSTALL_ERROR, {"errorCode", "markerName"}}, - {TELEMETRY_MARKER_LAUNCH_TIME, {"totalLaunchTime", "appManagerLaunchTime", "packageManagerLockTime", "lifecycleManagerSpawnTime", "windowManagerCreateDisplayTime", "runtimeManagerRunTime", "storageManagerLaunchTime", "fireboltGatewayLaunchTime", "appId", "appInstanceId", "appVersion", "runtimeId", "runtimeVersion", "launchType", "markerName"}}, - {TELEMETRY_MARKER_LAUNCH_ERROR, {"errorCode", "markerName"}}, - {TELEMETRY_MARKER_CLOSE_TIME, {"totalCloseTime", "appManagerCloseTime", "packageManagerUnlockTime", "lifecycleManagerSetTargetStateTime", "windowManagerDestroyTime", "runtimeManagerTerminateTime", "storageManagerTime", "fireboltGatewayTerminateTime", "appId", "appInstanceId", "appVersion", "closeType", "markerName"}}, - {TELEMETRY_MARKER_CLOSE_ERROR, {"errorCode", "markerName"}}, - {TELEMETRY_MARKER_SUSPEND_TIME, {"lifecycleManagerSetTargetStateTime", "runtimeManagerSuspendTime", "appId", "appInstanceId", "markerName"}}, - {TELEMETRY_MARKER_RESUME_TIME, {"lifecycleManagerSetTargetStateTime", "runtimeManagerResumeTime", "appId", "appInstanceId", "markerName"}}, - {TELEMETRY_MARKER_HIBERNATE_TIME, {"lifecycleManagerSetTargetStateTime", "runtimeManagerHibernateTime", "appId", "appInstanceId", "markerName"}}, - {TELEMETRY_MARKER_WAKE_TIME, {"lifecycleManagerSetTargetStateTime", "runtimeManagerWakeTime", "appId", "appInstanceId", "markerName"}}, - {TELEMETRY_MARKER_APP_CRASHED, {"crashReason", "appId", "appInstanceId", "markerName"}}, -}; diff --git a/TelemetryMetrics/TelemetryMetrics.conf.in b/TelemetryMetrics/TelemetryMetrics.conf.in deleted file mode 100755 index 0a9e45d..0000000 --- a/TelemetryMetrics/TelemetryMetrics.conf.in +++ /dev/null @@ -1,11 +0,0 @@ -precondition = ["Platform"] -callsign = "org.rdk.TelemetryMetrics" -autostart = "@PLUGIN_TELEMETRY_METRICS_AUTOSTART@" -startuporder = "@PLUGIN_TELEMETRY_METRICS_STARTUPORDER@" - -configuration = JSON() - -rootobject = JSON() -rootobject.add("mode", "@PLUGIN_TELEMETRY_METRICS_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) \ No newline at end of file diff --git a/TelemetryMetrics/TelemetryMetrics.config b/TelemetryMetrics/TelemetryMetrics.config deleted file mode 100755 index 0d69c98..0000000 --- a/TelemetryMetrics/TelemetryMetrics.config +++ /dev/null @@ -1,16 +0,0 @@ -set (autostart ${PLUGIN_TELEMETRY_METRICS_AUTOSTART}) -set (preconditions Platform) -set (callsign "org.rdk.TelemetryMetrics") - -if(PLUGIN_TELEMETRY_METRICS_STARTUPORDER) -set (startuporder ${PLUGIN_TELEMETRY_METRICS_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_TELEMETRY_METRICS_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) \ No newline at end of file diff --git a/TelemetryMetrics/TelemetryMetrics.cpp b/TelemetryMetrics/TelemetryMetrics.cpp deleted file mode 100755 index 044e3ec..0000000 --- a/TelemetryMetrics/TelemetryMetrics.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -#include "TelemetryMetrics.h" - -const string WPEFramework::Plugin::TelemetryMetrics::SERVICE_NAME = "org.rdk.TelemetryMetrics"; - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - TELEMETRY_METRICS_API_VERSION_NUMBER_MAJOR, TELEMETRY_METRICS_API_VERSION_NUMBER_MINOR, TELEMETRY_METRICS_API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register TelemetryMetrics module as wpeframework plugin - **/ - SERVICE_REGISTRATION(TelemetryMetrics, TELEMETRY_METRICS_API_VERSION_NUMBER_MAJOR, TELEMETRY_METRICS_API_VERSION_NUMBER_MINOR, TELEMETRY_METRICS_API_VERSION_NUMBER_PATCH); - - TelemetryMetrics::TelemetryMetrics() : - mCurrentService(nullptr), - mConnectionId(0), - mTelemetryMetricsImpl(nullptr) - { - SYSLOG(Logging::Startup, (_T("TelemetryMetrics Constructor"))); - } - - TelemetryMetrics::~TelemetryMetrics() - { - SYSLOG(Logging::Shutdown, (string(_T("TelemetryMetrics Destructor")))); - } - - const string TelemetryMetrics::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == mCurrentService); - ASSERT(nullptr == mTelemetryMetricsImpl); - ASSERT(0 == mConnectionId); - - SYSLOG(Logging::Startup, (_T("TelemetryMetrics::Initialize: PID=%u"), getpid())); - mCurrentService = service; - if (nullptr != mCurrentService) - { - mCurrentService->AddRef(); - if (nullptr == (mTelemetryMetricsImpl = mCurrentService->Root(mConnectionId, 5000, _T("TelemetryMetricsImplementation")))) - { - SYSLOG(Logging::Startup, (_T("TelemetryMetrics::Initialize: object creation failed"))); - message = _T("TelemetryMetrics plugin could not be initialised"); - } - } - else - { - SYSLOG(Logging::Startup, (_T("TelemetryMetrics::Initialize: service is not valid"))); - message = _T("TelemetryMetrics plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void TelemetryMetrics::Deinitialize(PluginHost::IShell* service) - { - ASSERT(mCurrentService == service); - - SYSLOG(Logging::Shutdown, (string(_T("TelemetryMetrics::Deinitialize")))); - - if (nullptr != mTelemetryMetricsImpl) - { - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(mConnectionId); - //VARIABLE_IS_NOT_USED uint32_t result = mTelemetryMetricsImpl->Release(); - if (mTelemetryMetricsImpl->Release() != Core::ERROR_DESTRUCTION_SUCCEEDED) { - SYSLOG(Logging::Shutdown, (_T("TelemetryMetrics Plugin is not properly destructed."))); - } - - mTelemetryMetricsImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - mConnectionId = 0; - mCurrentService->Release(); - mCurrentService = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("TelemetryMetrics de-initialised")))); - } - - string TelemetryMetrics::Information() const - { - // No additional info to report - return (string()); - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/TelemetryMetrics/TelemetryMetrics.h b/TelemetryMetrics/TelemetryMetrics.h deleted file mode 100755 index d94b3c4..0000000 --- a/TelemetryMetrics/TelemetryMetrics.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include - -namespace WPEFramework { -namespace Plugin { - - class TelemetryMetrics: public PluginHost::IPlugin - { - public: - TelemetryMetrics(const TelemetryMetrics&) = delete; - TelemetryMetrics& operator=(const TelemetryMetrics&) = delete; - - TelemetryMetrics(); - virtual ~TelemetryMetrics(); - - BEGIN_INTERFACE_MAP(TelemetryMetrics) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_AGGREGATE(Exchange::ITelemetryMetrics, mTelemetryMetricsImpl) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - PluginHost::IShell* mCurrentService{}; - uint32_t mConnectionId{}; - Exchange::ITelemetryMetrics* mTelemetryMetricsImpl{}; - - public /* constants */: - static const string SERVICE_NAME; - - }; - -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/TelemetryMetrics/TelemetryMetricsImplementation.cpp b/TelemetryMetrics/TelemetryMetricsImplementation.cpp deleted file mode 100755 index 06bc11f..0000000 --- a/TelemetryMetrics/TelemetryMetricsImplementation.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include "TelemetryMetricsImplementation.h" -#include "UtilsLogging.h" -#include "TelemetryFilters.h" - - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(TelemetryMetricsImplementation, 1, 0); - - TelemetryMetricsImplementation::TelemetryMetricsImplementation() - { - LOGINFO("Create TelemetryMetricsImplementation Instance"); - t2_init((char *) "TelemetryMetrics"); - } - - TelemetryMetricsImplementation::~TelemetryMetricsImplementation() - { - t2_uninit(); - LOGINFO("Delete TelemetryMetricsImplementation Instance"); - } - - std::string generateRecordId(const std::string& id, const std::string& name) - { - if (id.empty() || name.empty()) - { - LOGERR("Error: ID or Name is empty."); - return ""; - } - - return id +":" + name; - } - -/* This function attempts to parse a JSON-formatted string containing metrics, - * validates the parsed data, and then merges it into an internal metrics record - * map keyed by a generated record ID. - * - * @param id The unique identifier - * @param metrics A JSON-formatted string representing the metrics data to record. - * @param markerName An string used to generate a unique record key. - * - * @return Core::hresult - * - Core::ERROR_NONE on success. - * - Core::ERROR_GENERAL if parsing fails or input is invalid. - */ - Core::hresult TelemetryMetricsImplementation::Record(const std::string& id, const std::string& metrics, const std::string& markerName) - { - Core::hresult status = Core::ERROR_GENERAL; - - /* Create JSON parser builder and CharReader for parsing JSON strings */ - Json::CharReaderBuilder builder; - std::unique_ptr reader(builder.newCharReader()); - - Json::Value newMetrics = Json::objectValue; - std::string errs = ""; - - /* Parse the input JSON string into newMetrics */ - if (!reader->parse(metrics.c_str(), metrics.c_str() + metrics.size(), &newMetrics, &errs)) - { - LOGERR("JSON parse failed: %s", errs.c_str()); - } - else if (!newMetrics.isObject()) - { - LOGERR("Input metrics must be a JSON object"); - } - else - { - std::lock_guard lock(mMetricsMutex); - std::string recordId = generateRecordId(id, markerName); - if(!recordId.empty()) - { - bool isNewRecord = (mMetricsRecord.find(recordId) == mMetricsRecord.end()); - - /* Get existing metrics for the key or creates new entry if not exist */ - Json::Value& existing = mMetricsRecord[recordId]; - - /* store markerName inside JSON value the first time */ - if (isNewRecord) - { - existing["markerName"] = markerName; - LOGINFO("Storing new markerName '%s' for recordId '%s'", markerName.c_str(), recordId.c_str()); - } - else - { - LOGINFO("RecordId '%s' already exists. markerName unchanged.", recordId.c_str()); - } - - /* Merge each metric from newMetrics into existing record */ - for (const std::string& metricKey : newMetrics.getMemberNames()) - { - if (existing.isMember(metricKey)) - { - LOGWARN("Record:'%s' Overwriting key '%s'", recordId.c_str(), metricKey.c_str()); - } - else - { - LOGINFO("Record:'%s' Adding new key '%s'", recordId.c_str(), metricKey.c_str()); - } - existing[metricKey] = newMetrics[metricKey]; - } - status = Core::ERROR_NONE; - } - } - - return status; - } - - /* Publishes the collected telemetry metrics. - * - * This method is responsible for sending or flushing the internally stored - * metrics records to the telemetry. - * - * @param id The unique identifier - * @param markerName An string used to generate a unique record key. - * - * @return Core::hresult - * - Core::ERROR_NONE on success. - * - Core::ERROR_GENERAL if parsing fails or input is invalid. - */ - Core::hresult TelemetryMetricsImplementation::Publish(const std::string& id, const std::string& markerName) - { - Core::hresult status = Core::ERROR_GENERAL; - - std::string recordId = generateRecordId(id, markerName); - Json::Value filteredMetrics =Json::objectValue; - std::string appInstanceId = ""; - std::string matchedOtherRecordId = ""; - std::unordered_set filterKeys ={}; - - bool error = false; - - /* Lock mutex once for the entire critical section */ - std::lock_guard lock(mMetricsMutex); - - /* Retrieve filter Names for the given markerName*/ - auto filterIt = markerFilters.find(markerName); - if (filterIt != markerFilters.end()) - { - filterKeys = filterIt->second; - } - else - { - LOGERR("Filter list not found for marker: %s", markerName.c_str()); - error = true; - } - - if (!error) - { - /* Filter current recordMetrics and extract appInstanceId */ - auto currentRecordIt = mMetricsRecord.find(recordId); - if (currentRecordIt == mMetricsRecord.end()) - { - LOGERR("Current record not found: %s", recordId.c_str()); - error = true; - } - else - { - const Json::Value& currentMetrics = currentRecordIt->second; - - for (const std::string& key : currentMetrics.getMemberNames()) - { - if (filterKeys.count(key)) - { - filteredMetrics[key] = currentMetrics[key]; - if (key == "appInstanceId") - { - appInstanceId = currentMetrics[key].asString(); - } - } - else - { - LOGWARN("Key '%s' not allowed by filter for marker '%s'", key.c_str(), markerName.c_str()); - } - } - } - } - - /* Merge other recordMetrics with the same appInstanceId and markerName */ - if (!error && !appInstanceId.empty()) - { - std::string appInstancePrefix = appInstanceId + ":"; - - for (const auto& entry : mMetricsRecord) - { - const std::string& otherRecordId = entry.first; - if (otherRecordId == recordId) - continue; - - if (otherRecordId.compare(0, appInstancePrefix.size(), appInstancePrefix) == 0) - { - const std::string otherMarkerName = otherRecordId.substr(appInstancePrefix.size()); - - /* Merge if markerName Matches */ - if (otherMarkerName == markerName) - { - const Json::Value& otherMetrics = entry.second; - - for (const std::string& key : otherMetrics.getMemberNames()) - { - if (filterKeys.count(key)) - { - filteredMetrics[key] = otherMetrics[key]; - LOGINFO("Merged key '%s' from '%s' into current record", key.c_str(), otherRecordId.c_str()); - } - } - matchedOtherRecordId = otherRecordId; - LOGINFO("Merged record: '%s' into '%s'", otherRecordId.c_str(), recordId.c_str()); - break; - } - } - } - } - - /*Publish metrics if no errors occurred */ - if (!error) - { - Json::StreamWriterBuilder writerBuilder; - writerBuilder["indentation"] = " "; - std::string publishMetrics = Json::writeString(writerBuilder, filteredMetrics); - - LOGINFO("Publishing metrics for RecordId:'%s' publishMetrics:'%s'", recordId.c_str(), publishMetrics.c_str()); - t2_event_s((char*)markerName.c_str(), (char*)publishMetrics.c_str()); - - /* Remove Published Record */ - mMetricsRecord.erase(recordId); - if (!matchedOtherRecordId.empty()) - { - mMetricsRecord.erase(matchedOtherRecordId); - } - LOGINFO("Cleared published record: %s", recordId.c_str()); - - status = Core::ERROR_NONE; - } - - return status; - } -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/TelemetryMetrics/TelemetryMetricsImplementation.h b/TelemetryMetrics/TelemetryMetricsImplementation.h deleted file mode 100755 index d939fd4..0000000 --- a/TelemetryMetrics/TelemetryMetricsImplementation.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include - - -namespace WPEFramework { -namespace Plugin { - - class TelemetryMetricsImplementation : public Exchange::ITelemetryMetrics { - - public: - - TelemetryMetricsImplementation(); - ~TelemetryMetricsImplementation() override; - - TelemetryMetricsImplementation(const TelemetryMetricsImplementation&) = delete; - TelemetryMetricsImplementation& operator=(const TelemetryMetricsImplementation&) = delete; - - BEGIN_INTERFACE_MAP(TelemetryMetricsImplementation) - INTERFACE_ENTRY(Exchange::ITelemetryMetrics) - END_INTERFACE_MAP - - Core::hresult Record(const string& id, const string& metrics, const string& name) override; - Core::hresult Publish(const string& id, const string& name) override; - - private: - std::unordered_map mMetricsRecord; - std::mutex mMetricsMutex; - }; -} /* namespace Plugin */ -} /* namespace WPEFramework */ diff --git a/Tests/L1Tests/CMakeLists.txt b/Tests/L1Tests/CMakeLists.txt index fbc3c00..8e62a60 100755 --- a/Tests/L1Tests/CMakeLists.txt +++ b/Tests/L1Tests/CMakeLists.txt @@ -24,10 +24,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(${NAMESPACE}Plugins REQUIRED) -set (TEST_SRC - tests/test_UtilsFile.cpp -) - set (TEST_LIB ${NAMESPACE}Plugins::${NAMESPACE}Plugins ) @@ -101,82 +97,11 @@ macro(add_plugin_test plugin_name test_files) add_plugin_test_ex(${plugin_opt} "${test_files}" "../../${plugin_name}" "${NAMESPACE}${plugin_name}") endmacro() -# PLUGIN_USBDEVICE -set (USBDEVICE_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/USBDevice ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (USBDEVICE_LIBS ${NAMESPACE}USBDevice ${NAMESPACE}USBDeviceImplementation) -add_plugin_test_ex(PLUGIN_USBDEVICE tests/test_USBDevice.cpp "${USBDEVICE_INC}" "${USBDEVICE_LIBS}") - -# PLUGIN_USB_MASS_STORAGE -set (USB_MASS_STORAGE_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/USBMassStorage ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (USB_MASS_STORAGE_LIBS ${NAMESPACE}USBMassStorage ${NAMESPACE}USBMassStorageImplementation) -add_plugin_test_ex(PLUGIN_USB_MASS_STORAGE tests/test_USBMassStorage.cpp "${USB_MASS_STORAGE_INC}" "${USB_MASS_STORAGE_LIBS}") - -# PLUGIN_TELEMETRY -set (TELEMETRY_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/Telemetry ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (TELEMETRY_LIBS ${NAMESPACE}Telemetry ${NAMESPACE}TelemetryImplementation) -add_plugin_test_ex(PLUGIN_TELEMETRY tests/test_Telemetry.cpp "${TELEMETRY_INC}" "${TELEMETRY_LIBS}") - -# PLUGIN_APPMANAGER -set (APPMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/AppManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (APPMANAGER_LIBS ${NAMESPACE}AppManager ${NAMESPACE}AppManagerImplementation) -add_plugin_test_ex(PLUGIN_APPMANAGER tests/test_AppManager.cpp "${APPMANAGER_INC}" "${APPMANAGER_LIBS}") - -# PLUGIN_OCICONTAINER -set (OCICONTAINER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/OCIContainer ${CMAKE_SOURCE_DIR}/../entservices-infra/OCIContainer/stubs) -set (OCICONTAINER_LIBS ${NAMESPACE}OCIContainer) -add_plugin_test_ex(PLUGIN_OCICONTAINER tests/test_OCIContainer.cpp "${OCICONTAINER_INC}" "${OCICONTAINER_LIBS}") - -# PLUGIN_RUNTIME_MANAGER -set (RUNTIMEMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/RuntimeManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (RUNTIMEMANAGER_LIBS ${NAMESPACE}RuntimeManager ${NAMESPACE}RuntimeManagerImplementation) -add_plugin_test_ex(PLUGIN_RUNTIME_MANAGER tests/test_RunTimeManager.cpp "${RUNTIMEMANAGER_INC}" "${RUNTIMEMANAGER_LIBS}") - - # PLUGIN_USERSETTINGS -set (USERSETTINGS_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/UserSettings ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) +set (USERSETTINGS_INC ${CMAKE_SOURCE_DIR}/plugin ${CMAKE_SOURCE_DIR}/helpers) set (USERSETTINGS_LIBS ${NAMESPACE}UserSettings ${NAMESPACE}UserSettingsImplementation) add_plugin_test_ex(PLUGIN_USERSETTINGS tests/test_UserSettings.cpp "${USERSETTINGS_INC}" "${USERSETTINGS_LIBS}") -# PLUGIN_RESOURCEMANAGER -set (RESOURCEMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/ResourceManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -add_plugin_test_ex(PLUGIN_RESOURCEMANAGER tests/test_ResourceManager.cpp "${RESOURCEMANAGER_INC}" "${NAMESPACE}ResourceManager") - -#PLUGIN_STORAGE_MANAGER -set (STORAGE_MANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/StorageManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (STORAGE_MANAGER_LIBS ${NAMESPACE}StorageManager ${NAMESPACE}StorageManagerImplementation) -add_plugin_test_ex(PLUGIN_STORAGE_MANAGER tests/test_StorageManager.cpp "${STORAGE_MANAGER_INC}" "${STORAGE_MANAGER_LIBS}") - -# PLUGIN_LIFECYCLE_MANAGER -set (LIFECYCLEMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/LifecycleManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (LIFECYCLEMANAGER_LIBS ${NAMESPACE}LifecycleManager) -add_plugin_test_ex(PLUGIN_LIFECYCLE_MANAGER tests/test_LifecycleManager.cpp "${LIFECYCLEMANAGER_INC}" "${LIFECYCLEMANAGER_LIBS}") - -# PLUGIN_MESSAGECONTROL -set (MESSAGECONTROL_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/MessageControl ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (MESSAGECONTROL_LIBS ${NAMESPACE}MessageControl) -add_plugin_test_ex(PLUGIN_MESSAGECONTROL tests/test_MessageControl.cpp "${MESSAGECONTROL_INC}" "${MESSAGECONTROL_LIBS}") - - -# PLUGIN_MIGRATION -set (MIGRATION_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/Migration ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (MIGRATION_LIBS ${NAMESPACE}Migration ${NAMESPACE}MigrationImplementation) -add_plugin_test_ex(PLUGIN_MIGRATION tests/test_Migration.cpp "${MIGRATION_INC}" "${MIGRATION_LIBS}") - -# PLUGIN_PREINSTALL_MANAGER -set (PREINSTALL_MANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/PreinstallManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (PREINSTALL_MANAGER_LIBS ${NAMESPACE}PreinstallManager ${NAMESPACE}PreinstallManagerImplementation) -add_plugin_test_ex(PLUGIN_PREINSTALL_MANAGER tests/test_PreinstallManager.cpp "${PREINSTALL_MANAGER_INC}" "${PREINSTALL_MANAGER_LIBS}") - -# PLUGIN_PACKAGE_MANAGER -set (PACKAGEMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/PackageManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (PACKAGEMANAGER_LIBS ${NAMESPACE}PackageManagerRDKEMS) -add_plugin_test_ex(PLUGIN_PACKAGE_MANAGER tests/test_PackageManager.cpp "${PACKAGEMANAGER_INC}" "${PACKAGEMANAGER_LIBS}") - -#PLUGIN_DOWNLOAD_MANAGER -set (DOWNLOADMANAGER_INC ${CMAKE_SOURCE_DIR}/../entservices-infra/DownloadManager ${CMAKE_SOURCE_DIR}/../entservices-infra/helpers) -set (DOWNLOADMANAGER_LIBS ${NAMESPACE}DownloadManager ${NAMESPACE}DownloadManagerImplementation) -add_plugin_test_ex(PLUGIN_DOWNLOADMANAGER tests/test_DownloadManager.cpp "${DOWNLOADMANAGER_INC}" "${DOWNLOADMANAGER_LIBS}") - add_library(${MODULE_NAME} SHARED ${TEST_SRC}) if (RDK_SERVICES_L1_TEST) diff --git a/Tests/L1Tests/tests/test_AppManager.cpp b/Tests/L1Tests/tests/test_AppManager.cpp deleted file mode 100755 index a63052f..0000000 --- a/Tests/L1Tests/tests/test_AppManager.cpp +++ /dev/null @@ -1,3249 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include -#include -#include -#include -#include -#include - -#include "AppManager.h" -#include "AppManagerImplementation.h" -#include "ServiceMock.h" -#include "LifecycleManagerMock.h" -#include "PackageManagerMock.h" -#include "StorageManagerMock.h" -#include "Store2Mock.h" -#include "COMLinkMock.h" -#include "ThunderPortability.h" -#include "Module.h" -#include "WorkerPoolImplementation.h" -#include "WrapsMock.h" -#include "FactoriesImplementation.h" - - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -#define TIMEOUT (50000) -#define APPMANAGER_APP_ID "com.test.app" -#define APPMANAGER_EMPTY_APP_ID "" -#define APPMANAGER_APP_VERSION "1.2.8" -#define APPMANAGER_APP_DIGEST "" -#define APPMANAGER_APP_STATE Exchange::IPackageInstaller::InstallState::INSTALLED -#define APPMANAGER_APP_STATE_STR "INTERACTIVE_APP" -#define APPMANAGER_APP_SIZE 0 -#define APPMANAGER_WRONG_APP_ID "com.wrongtest.app" -#define APPMANAGER_APP_INTENT "test.intent" -#define APPMANAGER_APP_LAUNCHARGS "test.arguments" -#define APPMANAGER_APP_INSTANCE "testAppInstance" -#define APPMANAGER_APP_UNPACKEDPATH "/media/apps/sky/packages/Hulu/data.img" -#define PERSISTENT_STORE_KEY "DUMMY" -#define PERSISTENT_STORE_VALUE "DUMMY_VALUE" -#define APPMANAGER_PACKAGEID "testPackageID" -#define APPMANAGER_INSTALLSTATUS_INSTALLED "INSTALLED" -#define APPMANAGER_INSTALLSTATUS_UNINSTALLED "UNINSTALLED" -#define TEST_JSON_INSTALLED_PACKAGE R"([{"packageId":"YouTube","version":"100.1.30+rialto","state":"INSTALLED"}])" - -typedef enum : uint32_t { - AppManager_StateInvalid = 0x00000000, - AppManager_onAppLifecycleStateChanged = 0x00000001, - AppManager_onAppInstalled = 0x00000002, - AppManager_onAppLaunchRequest = 0x00000003, - AppManager_onAppUnloaded = 0x00000004 -} AppManagerL1test_async_events_t; - -struct ExpectedAppLifecycleEvent { - std::string appId; - std::string appInstanceId; - std::string intent; - std::string version; - std::string source; - Exchange::IAppManager::AppLifecycleState newState; - Exchange::IAppManager::AppLifecycleState oldState; - Exchange::IAppManager::AppErrorReason errorReason; -}; -using ::testing::NiceMock; -using namespace WPEFramework; - -namespace { -const string callSign = _T("AppManager"); -} -class AppManagerTest : public ::testing::Test { -protected: - ServiceMock* mServiceMock = nullptr; - LifecycleManagerMock* mLifecycleManagerMock = nullptr; - LifecycleManagerStateMock* mLifecycleManagerStateMock = nullptr; - PackageManagerMock* mPackageManagerMock = nullptr; - PackageInstallerMock* mPackageInstallerMock = nullptr; - Store2Mock* mStore2Mock = nullptr; - StorageManagerMock* mStorageManagerMock = nullptr; - WrapsImplMock *p_wrapsImplMock = nullptr; - Core::JSONRPC::Message message; - FactoriesImplementation factoriesImplementation; - PLUGINHOST_DISPATCHER *dispatcher; - - - Core::ProxyType plugin; - Plugin::AppManagerImplementation *mAppManagerImpl; - Exchange::IPackageInstaller::INotification* mPackageManagerNotification_cb = nullptr; - Exchange::ILifecycleManagerState::INotification* mLifecycleManagerStateNotification_cb = nullptr; - Exchange::IAppManager::INotification* mAppManagerNotification = nullptr; - - Core::ProxyType workerPool; - Core::JSONRPC::Handler& mJsonRpcHandler; - DECL_CORE_JSONRPC_CONX connection; - string mJsonRpcResponse; - std::mutex mPreLoadMutex; - std::condition_variable mPreLoadCV; - bool mPreLoadSpawmCalled = false; - - void createAppManagerImpl() - { - mServiceMock = new NiceMock; - - TEST_LOG("In createAppManagerImpl!"); - EXPECT_EQ(string(""), plugin->Initialize(mServiceMock)); - mAppManagerImpl = Plugin::AppManagerImplementation::getInstance(); - } - - void releaseAppManagerImpl() - { - TEST_LOG("In releaseAppManagerImpl!"); - plugin->Deinitialize(mServiceMock); - delete mServiceMock; - mAppManagerImpl = nullptr; - } - - Core::hresult createResources() - { - Core::hresult status = Core::ERROR_GENERAL; - mServiceMock = new NiceMock; - mLifecycleManagerMock = new NiceMock; - mLifecycleManagerStateMock = new NiceMock; - mPackageManagerMock = new NiceMock; - mPackageInstallerMock = new NiceMock; - mStorageManagerMock = new NiceMock; - mStore2Mock = new NiceMock; - p_wrapsImplMock = new NiceMock ; - Wraps::setImpl(p_wrapsImplMock); - - PluginHost::IFactories::Assign(&factoriesImplementation); - dispatcher = static_cast( - plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); - dispatcher->Activate(mServiceMock); - TEST_LOG("In createResources!"); - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t id, const std::string& name) -> void* { - if (name == "org.rdk.LifecycleManager") { - if(id == Exchange::ILifecycleManager::ID) { - return reinterpret_cast(mLifecycleManagerMock); - } - else if(id == Exchange::ILifecycleManagerState::ID) { - return reinterpret_cast(mLifecycleManagerStateMock); - } - } else if (name == "org.rdk.PersistentStore") { - return reinterpret_cast(mStore2Mock); - } else if (name == "org.rdk.StorageManager") { - return reinterpret_cast(mStorageManagerMock); - } else if (name == "org.rdk.PackageManagerRDKEMS") { - if (id == Exchange::IPackageHandler::ID) { - return reinterpret_cast(mPackageManagerMock); - } - else if (id == Exchange::IPackageInstaller::ID){ - return reinterpret_cast(mPackageInstallerMock); - } - } - return nullptr; - })); - - EXPECT_CALL(*mPackageInstallerMock, Register(::testing::_)) - .WillOnce(::testing::Invoke( - [&](Exchange::IPackageInstaller::INotification* notification) { - mPackageManagerNotification_cb = notification; - return Core::ERROR_NONE; - })); - - ON_CALL(*mLifecycleManagerStateMock, Register(::testing::_)) - .WillByDefault(::testing::Invoke( - [&](Exchange::ILifecycleManagerState::INotification* notification) { - mLifecycleManagerStateNotification_cb = notification; - return Core::ERROR_NONE; - })); - - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault(::testing::Return(-1)); - - EXPECT_EQ(string(""), plugin->Initialize(mServiceMock)); - mAppManagerImpl = Plugin::AppManagerImplementation::getInstance(); - TEST_LOG("createResources - All done!"); - status = Core::ERROR_NONE; - - return status; - } - - void releaseResources() - { - TEST_LOG("In releaseResources!"); - - if (mLifecycleManagerStateMock != nullptr && mLifecycleManagerStateNotification_cb != nullptr) - { - ON_CALL(*mLifecycleManagerStateMock, Unregister(::testing::_)) - .WillByDefault(::testing::Invoke([&]() { - return 0; - })); - mLifecycleManagerStateNotification_cb = nullptr; - } - if (mPackageInstallerMock != nullptr && mPackageManagerNotification_cb != nullptr) - { - ON_CALL(*mPackageInstallerMock, Unregister(::testing::_)) - .WillByDefault(::testing::Invoke([&]() { - return 0; - })); - mPackageManagerNotification_cb = nullptr; - } - - if (mLifecycleManagerMock != nullptr) - { - EXPECT_CALL(*mLifecycleManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mLifecycleManagerMock; - return 0; - })); - } - if (mLifecycleManagerStateMock != nullptr) - { - EXPECT_CALL(*mLifecycleManagerStateMock, Unregister(::testing::_)) - .WillOnce(::testing::Invoke( - [&]() { - return 0; - })); - EXPECT_CALL(*mLifecycleManagerStateMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mLifecycleManagerStateMock; - return 0; - })); - } - if (mPackageManagerMock != nullptr) - { - EXPECT_CALL(*mPackageManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mPackageManagerMock; - return 0; - })); - } - if (mPackageInstallerMock != nullptr) - { - EXPECT_CALL(*mPackageInstallerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mPackageInstallerMock; - return 0; - })); - } - if (mStore2Mock != nullptr) - { - EXPECT_CALL(*mStore2Mock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mStore2Mock; - return 0; - })); - } - - Wraps::setImpl(nullptr); - if (p_wrapsImplMock != nullptr) - { - delete p_wrapsImplMock; - p_wrapsImplMock = nullptr; - } - - if (mStorageManagerMock != nullptr) - { - EXPECT_CALL(*mStorageManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mStorageManagerMock; - return 0; - })); - } - dispatcher->Deactivate(); - dispatcher->Release(); - - plugin->Deinitialize(mServiceMock); - delete mServiceMock; - mAppManagerImpl = nullptr; - } - AppManagerTest() - : plugin(Core::ProxyType::Create()), - workerPool(Core::ProxyType::Create(2, Core::Thread::DefaultStackSize(), 16)), - mJsonRpcHandler(*plugin), - INIT_CONX(1, 0) - { - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - - virtual ~AppManagerTest() override - { - TEST_LOG("Delete ~AppManagerTest Instance!"); - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - } - std::string GetPackageInfoInJSON() - { - std::string apps_str = ""; - JsonObject package; - JsonArray installedAppsArray; - - package["appId"] = APPMANAGER_APP_ID; - package["versionString"] = APPMANAGER_APP_VERSION; - package["type"] = APPMANAGER_APP_STATE_STR; - package["lastActiveTime"] = ""; - package["lastActiveIndex"] = ""; - - installedAppsArray.Add(package); - installedAppsArray.ToString(apps_str); - - return apps_str; - } - - auto FillPackageIterator() - { - std::list packageList; - Exchange::IPackageInstaller::Package package_1; - - package_1.packageId = APPMANAGER_APP_ID; - package_1.version = APPMANAGER_APP_VERSION; - package_1.digest = APPMANAGER_APP_DIGEST; - package_1.state = APPMANAGER_APP_STATE; - package_1.sizeKb = APPMANAGER_APP_SIZE; - - packageList.emplace_back(package_1); - return Core::Service>::Create(packageList); - } - - auto FillLoadedAppsIterator() - { - std::list loadedAppInfoList; - - WPEFramework::Exchange::IAppManager::LoadedAppInfo app_1, app_2; - app_1.appId = "NexTennis"; - app_1.appInstanceId = "0295effd-2883-44ed-b614-471e3f682762"; - app_1.activeSessionId = ""; - app_1.targetLifecycleState = WPEFramework::Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - app_1.lifecycleState = WPEFramework::Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - - app_2.appId = "uktv"; - app_2.appInstanceId = "67fa75b6-0c85-43d4-a591-fd29e7214be5"; - app_2.activeSessionId = ""; - app_2.targetLifecycleState = WPEFramework::Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - app_2.lifecycleState = WPEFramework::Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - - loadedAppInfoList.emplace_back(app_1); - loadedAppInfoList.emplace_back(app_2); - return Core::Service>::Create(loadedAppInfoList); - } - - void LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState state) - { - const std::string launchArgs = APPMANAGER_APP_LAUNCHARGS; - TEST_LOG("LaunchAppPreRequisite with state: %d", state); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillRepeatedly([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mPackageManagerMock, Lock(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string &packageId, const string &version, const Exchange::IPackageHandler::LockReason &lockReason, uint32_t &lockId /* @out */, string &unpackedPath /* @out */, Exchange::RuntimeConfig &configMetadata /* @out */, Exchange::IPackageHandler::ILockIterator*& appMetadata /* @out */) { - lockId = 1; - unpackedPath = APPMANAGER_APP_UNPACKEDPATH; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mLifecycleManagerMock, IsAppLoaded(::testing::_, ::testing::_)) - .WillRepeatedly([&](const std::string &appId, bool &loaded) { - loaded = true; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mLifecycleManagerMock, SetTargetAppState(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string& appInstanceId , const Exchange::ILifecycleManager::LifecycleState targetLifecycleState , const string& launchIntent) { - return Core::ERROR_NONE; - }); - EXPECT_CALL(*mLifecycleManagerMock, SpawnApp(APPMANAGER_APP_ID, ::testing::_, ::testing::_, ::testing::_, launchArgs, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce([&](const string& appId, const string& launchIntent, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, - const Exchange::RuntimeConfig& runtimeConfigObject, const string& launchArgs, string& appInstanceId, string& errorReason, bool& success) { - appInstanceId = APPMANAGER_APP_INSTANCE; - errorReason = ""; - success = true; - return Core::ERROR_NONE; - }); - } - - void preLaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState state) - { - const std::string launchArgs = APPMANAGER_APP_LAUNCHARGS; - TEST_LOG("LaunchAppPreRequisite with state: %d", state); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillRepeatedly([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mPackageManagerMock, Lock(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string &packageId, const string &version, const Exchange::IPackageHandler::LockReason &lockReason, uint32_t &lockId /* @out */, string &unpackedPath /* @out */, Exchange::RuntimeConfig &configMetadata /* @out */, Exchange::IPackageHandler::ILockIterator*& appMetadata /* @out */) { - lockId = 1; - unpackedPath = APPMANAGER_APP_UNPACKEDPATH; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mLifecycleManagerMock, IsAppLoaded(::testing::_, ::testing::_)) - .WillRepeatedly([&](const std::string &appId, bool &loaded) { - loaded = true; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mLifecycleManagerMock, SetTargetAppState(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string& appInstanceId , const Exchange::ILifecycleManager::LifecycleState targetLifecycleState , const string& launchIntent) { - return Core::ERROR_NONE; - }); - EXPECT_CALL(*mLifecycleManagerMock, SpawnApp(APPMANAGER_APP_ID, ::testing::_, ::testing::_, ::testing::_, launchArgs, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce([&](const string& appId, const string& launchIntent, const Exchange::ILifecycleManager::LifecycleState targetLifecycleState, - const Exchange::RuntimeConfig& runtimeConfigObject, const string& launchArgs, string& appInstanceId, string& errorReason, bool& success) { - { - std::lock_guard lock(mPreLoadMutex); - mPreLoadSpawmCalled = true; - } - appInstanceId = APPMANAGER_APP_INSTANCE; - errorReason = ""; - success = true; - mPreLoadCV.notify_one(); - return Core::ERROR_NONE; - }); - } - - void UnloadAppAndUnlock() - { - EXPECT_CALL(*mLifecycleManagerMock, UnloadApp(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string& appInstanceId, string& errorReason, bool& success) { - success = true; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mPackageManagerMock, Unlock(APPMANAGER_APP_ID, ::testing::_)) - .WillOnce([&](const string &packageId, const string &version) { - return Core::ERROR_NONE; - }); - } -}; - -class NotificationHandler : public Exchange::IAppManager::INotification { - private: - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IAppManager::INotification) - END_INTERFACE_MAP - - public: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled = AppManager_StateInvalid; - - ExpectedAppLifecycleEvent m_expectedEvent; - NotificationHandler(){} - ~NotificationHandler(){} - void SetExpectedEvent(const ExpectedAppLifecycleEvent& expectedEvent) - { - m_expectedEvent = expectedEvent; - } - - void OnAppLifecycleStateChanged(const string& appId, const string& appInstanceId, const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) - { - m_event_signalled |= AppManager_onAppLifecycleStateChanged; - EXPECT_EQ(m_expectedEvent.appId, appId); - EXPECT_EQ(m_expectedEvent.appInstanceId, appInstanceId); - EXPECT_EQ(m_expectedEvent.newState, newState); - EXPECT_EQ(m_expectedEvent.oldState, oldState); - EXPECT_EQ(m_expectedEvent.errorReason, errorReason); - - m_condition_variable.notify_one(); - } - - void OnAppInstalled(const string& appId, const string& version) - { - std::unique_lock lock(m_mutex); - EXPECT_STREQ(m_expectedEvent.appId.c_str(), appId.c_str()); - EXPECT_STREQ(m_expectedEvent.version.c_str(), version.c_str()); - m_event_signalled |= AppManager_onAppInstalled; - - m_condition_variable.notify_one(); - } - - void OnAppLaunchRequest(const string& appId, const string& intent, const string& source) - { - std::unique_lock lock(m_mutex); - EXPECT_STREQ(m_expectedEvent.appId.c_str(), appId.c_str()); - EXPECT_STREQ(m_expectedEvent.intent.c_str(), intent.c_str()); - EXPECT_STREQ(m_expectedEvent.source.c_str(), source.c_str()); - m_event_signalled |= AppManager_onAppLaunchRequest; - - m_condition_variable.notify_one(); - } - - void OnAppUnloaded(const string& appId, const string& appInstanceId) - { - std::unique_lock lock(m_mutex); - EXPECT_STREQ(m_expectedEvent.appId.c_str(), appId.c_str()); - EXPECT_STREQ(m_expectedEvent.appInstanceId.c_str(), appInstanceId.c_str()); - m_event_signalled |= AppManager_onAppUnloaded; - - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, AppManagerL1test_async_events_t expected_status) - { - uint32_t signalled = AppManager_StateInvalid; - std::unique_lock lock(m_mutex); - auto now = std::chrono::steady_clock::now(); - auto timeout = std::chrono::milliseconds(timeout_ms); - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - signalled = m_event_signalled; - m_event_signalled = AppManager_StateInvalid; // reset for next use - return signalled; - } - }; - -/******************************************************************************************************************* - * Test Case for RegisteredMethodsUsingJsonRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying whether all methods exists or not - * Releasing the AppManager interface and all related test resources - ********************************************************************************************************************/ -TEST_F(AppManagerTest, RegisteredMethodsUsingJsonRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getInstalledApps"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("isInstalled"))); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getLoadedApps"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("launchApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("preloadApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("closeApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("terminateApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("startSystemApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("stopSystemApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("killApp"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("sendIntent"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("clearAppData"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("clearAllAppData"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getAppMetadata"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getAppProperty"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("setAppProperty"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getMaxRunningApps"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getMaxHibernatedApps"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getMaxHibernatedFlashUsage"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getMaxInactiveRamUsage"))); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetInstalledAppsUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API - * Verifying whether it returns the mocked package list filled or not - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, GetInstalledAppsUsingComRpcSuccess) -{ - Core::hresult status; - std::string apps = ""; - std::string jsonStr = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillRepeatedly([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetInstalledApps(apps)); - jsonStr = GetPackageInfoInJSON(); - EXPECT_STREQ(jsonStr.c_str(), apps.c_str()); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for GetInstalledAppsUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API - * Verifying whether it returns the mocked package list filled or not - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, GetInstalledAppsUsingJSONRpcSuccess) -{ - Core::hresult status; - std::string apps = ""; - std::string jsonStr = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillRepeatedly([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getInstalledApps"), _T("{\"apps\": \"\"}"), mJsonRpcResponse)); - jsonStr = GetPackageInfoInJSON(); - EXPECT_STREQ( - "[{\"appId\":\"com.test.app\",\"versionString\":\"1.2.8\",\"type\":\"INTERACTIVE_APP\",\"lastActiveTime\":\"\",\"lastActiveIndex\":\"\"}]", - mJsonRpcResponse.c_str()); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } - -} - -/* - * Test Case for GetInstalledAppsUsingComRpcFailurePackageManagerObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * PackageManager Interface object is not created and hence the API should return error - * Releasing the AppManager Interface object only - */ -TEST_F(AppManagerTest, GetInstalledAppsUsingComRpcFailurePackageManagerObjectIsNull) -{ - std::string apps = APPMANAGER_APP_ID; - - createAppManagerImpl(); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetInstalledApps(apps)); - releaseAppManagerImpl(); -} - -/* - * Test Case for GetInstalledAppsUsingComRpcFailurePackageListEmpty - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting empty package list - * Verifying the return of the API - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, GetInstalledAppsUsingComRpcFailurePackageListEmpty) -{ - Core::hresult status; - std::string apps = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - packages = nullptr; // make Package list empty - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetInstalledApps(apps)); - EXPECT_EQ(apps, ""); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetInstalledAppsUsingComRpcFailureListPackagesReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate error return - * Verifying the return of the API - * Releasing the AppManager Interface object and all related test resources - */ - -TEST_F(AppManagerTest, GetInstalledAppsUsingComRpcFailureListPackagesReturnError) -{ - Core::hresult status; - std::string apps = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetInstalledApps(apps)); - EXPECT_EQ(apps, ""); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for IsInstalledUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API as well the installed flag - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, IsInstalledUsingComRpcSuccess) -{ - Core::hresult status; - bool installed; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->IsInstalled(APPMANAGER_APP_ID, installed)); - EXPECT_EQ(installed, true); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for IsInstalledUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API as well the installed flag - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, IsInstalledUsingJSONRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("isInstalled"), request, mJsonRpcResponse)); - EXPECT_STREQ("true", mJsonRpcResponse.c_str()); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} -/* - * Test Case for IsInstalledUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API as well the installed flag - * Releasing the AppManager Interface object and all related test resources - */ - -TEST_F(AppManagerTest, IsInstalledUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - bool installed; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->IsInstalled(APPMANAGER_WRONG_APP_ID, installed)); - EXPECT_EQ(installed, false); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for IsInstalledUsingComRpcFailurePackageListEmpty - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API as well the installed flag - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, IsInstalledUsingComRpcFailurePackageListEmpty) -{ - Core::hresult status; - bool installed; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - // When package list is empty - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = nullptr; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->IsInstalled(APPMANAGER_APP_ID, installed)); - EXPECT_EQ(installed, false); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for IsInstalledUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate getting installed package list - * Verifying the return of the API as well the installed flag - * Releasing the AppManager Interface object and all related test resources - */ - -TEST_F(AppManagerTest, IsInstalledUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - bool installed; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->IsInstalled("", installed)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for IsInstalledUsingComRpcFailureListPackagesReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Calling FillPackageIterator() to fill one package info in the package iterator - * Setting Mock for ListPackages() to simulate error return - * Releasing the AppManager Interface object and all related test resources - */ -TEST_F(AppManagerTest, IsInstalledUsingComRpcFailureListPackagesReturnError) -{ - Core::hresult status; - bool installed; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillOnce([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); // Fill the package Info - packages = mockIterator; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->IsInstalled(APPMANAGER_APP_ID, installed)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for IsInstalledUsingComRpcFailurePackageManagerObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * PackageManager Interface object is not created and hence the API should return error - * Setting Mock for ListPackages() to simulate error return - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, IsInstalledUsingComRpcFailurePackageManagerObjectIsNull) -{ - bool installed; - - createAppManagerImpl(); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->IsInstalled(APPMANAGER_APP_ID, installed)); - releaseAppManagerImpl(); -} - -/* - * Test Case for LaunchAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and getting the app instance id - * Verifying the return of the API - * Setting Mock for OnAppLifecycleStateChanged() to simulate the app lifecycle state change - * Registering the notification handler to receive the app lifecycle state change event - * Simulating the app lifecycle state change event by calling OnAppLifecycleStateChanged() with expected parameters - * Waiting for the notification handler to receive the event and verifying the received event - * Verifying the received event matches the expected event - * Unregistering the notification handler - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = APPMANAGER_APP_INSTANCE; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - Core::Sink notification; - Plugin::AppManagerImplementation::AppInfo appInfo; - appInfo.appInstanceId = APPMANAGER_APP_INSTANCE; - uint32_t signalled = AppManager_StateInvalid; - appInfo.appNewState = Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - mAppManagerImpl->mAppInfo[APPMANAGER_APP_ID] = appInfo; - - /* Register the notification handler */ - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - /* Reset the signalled flag for next use */ - signalled = AppManager_StateInvalid; - mLifecycleManagerStateNotification_cb->OnAppLifecycleStateChanged( - APPMANAGER_APP_ID, - APPMANAGER_APP_INSTANCE, - Exchange::ILifecycleManager::LifecycleState::PAUSED, // Old state - Exchange::ILifecycleManager::LifecycleState::ACTIVE, // New state - "start" - ); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - mAppManagerImpl->Unregister(¬ification); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for LaunchAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Setting Mock for OnAppLifecycleStateChanged() to simulate the app lifecycle state change - * Registering the notification handler to receive the app lifecycle state change event - * Simulating the app lifecycle state change event by calling OnAppLifecycleStateChanged() with expected parameters - * Waiting for the notification handler to receive the event and verifying the received event - * Verifying the received event matches the expected event - * Unregistering the notification handler - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingJSONRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + - "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + - "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - })); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("launchApp"), request, mJsonRpcResponse)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - - Core::Event onAppLifecycleStateChanged(false, true); - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLifecycleStateChanged\",\"params\":{\"appId\":\"com.test.app\",\"appInstanceId\":\"testAppInstance\",\"newState\":\"APP_STATE_ACTIVE\",\"oldState\":\"APP_STATE_PAUSED\",\"errorReason\":\"APP_ERROR_NONE\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLifecycleStateChanged.SetEvent(); - - return Core::ERROR_NONE; - })); - ASSERT_NE(mLifecycleManagerStateNotification_cb, nullptr) - << "LifecycleManagerState notification callback is not registered"; - EVENT_SUBSCRIBE(0, _T("onAppLifecycleStateChanged"), _T("org.rdk.AppManager"), message); - mLifecycleManagerStateNotification_cb->OnAppLifecycleStateChanged( - APPMANAGER_APP_ID, - APPMANAGER_APP_INSTANCE, - Exchange::ILifecycleManager::LifecycleState::PAUSED, // Old state - Exchange::ILifecycleManager::LifecycleState::ACTIVE, // New state - "start" - ); - EXPECT_EQ(Core::ERROR_NONE, onAppLifecycleStateChanged.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLifecycleStateChanged"), _T("org.rdk.AppManager"), message); - if (status == Core::ERROR_NONE) { - releaseResources(); - } -} - -/* * Test Case for LaunchAppUsingCOMRPCSuspendedSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the app in suspended state - * Releasing the AppManager interface and all related test resources - */ -//TODO -/* -TEST_F(AppManagerTest, LaunchAppUsingCOMRPCSuspendedSuccess) -{ - Core::hresult status; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = APPMANAGER_APP_INSTANCE; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_SUSPENDED; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::SUSPENDED); - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, struct stat* info) { - // Simulate a successful stat call - if (info != nullptr) { - info->st_mode = S_IFREG | 0644; // Regular file with read/write permissions - } - // Simulate success - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} -*/ -/* - * Test Case for LaunchAppUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - expectedEvent.appId = APPMANAGER_WRONG_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NOT_INSTALLED; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_WRONG_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for LaunchAppUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting empty package list - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_INVALID_PARAMETER, mAppManagerImpl->LaunchApp("", APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for LaunchAppUsingComRpcSpawnAppFailure - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcSpawnAppFailure) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - // Mock the necessary calls - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_CALL(*mLifecycleManagerMock, SpawnApp(APPMANAGER_APP_ID, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce([&](const string& appId, const string& intent, const Exchange::ILifecycleManager::LifecycleState state, - const Exchange::RuntimeConfig& runtimeConfigObject, const string& launchArgs, string& appInstanceId, string& error, bool& success) { - error = "Failed to create LifecycleInterfaceConnector"; - success = false; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - // Verify that the notification handler received the expected event - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for LaunchAppUsingComRpcFailureIsAppLoadedReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate error return - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcFailureIsAppLoadedReturnError) -{ - Core::hresult status; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_PACKAGE_LOCK; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_CALL(*mLifecycleManagerMock, IsAppLoaded(::testing::_, ::testing::_)) - .WillOnce([&](const std::string &appId, bool &loaded) { - loaded = false; - return Core::ERROR_GENERAL; - }); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for LaunchAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ -TEST_F(AppManagerTest, LaunchAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - createAppManagerImpl(); - - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NOT_INSTALLED; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - releaseAppManagerImpl(); -} - -/* - * Test Case for PreloadAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, PreloadAppUsingComRpcSuccess) -{ - Core::hresult status; - std::string error = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - mPreLoadSpawmCalled = false; - - preLaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::PAUSED); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->PreloadApp(APPMANAGER_APP_ID, APPMANAGER_APP_LAUNCHARGS, error)); - { - std::unique_lock lock(mPreLoadMutex); - ASSERT_TRUE(mPreLoadCV.wait_for(lock, std::chrono::seconds(10), [&]{ return mPreLoadSpawmCalled; })); - } - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for PreloadAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, PreloadAppUsingJSONRpcSuccess) -{ - Core::hresult status; - std::string error = ""; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - mPreLoadSpawmCalled = false; - - preLaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::PAUSED); - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("preloadApp"), request, mJsonRpcResponse)); - { - std::unique_lock lock(mPreLoadMutex); - ASSERT_TRUE(mPreLoadCV.wait_for(lock, std::chrono::seconds(10), [&]{ return mPreLoadSpawmCalled; })); - } - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - - -/* - * Test Case for PreloadAppUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, PreloadAppUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - std::string error = ""; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - expectedEvent.appId = APPMANAGER_WRONG_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NOT_INSTALLED; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::PAUSED); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->PreloadApp(APPMANAGER_WRONG_APP_ID, APPMANAGER_APP_LAUNCHARGS, error)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for PreloadAppUsingComRpcFailureIsAppLoadedReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate error return - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ - -TEST_F(AppManagerTest, PreloadAppUsingComRpcFailureIsAppLoadedReturnError) -{ - Core::hresult status; - std::string error = ""; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_PACKAGE_LOCK; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::PAUSED); - - EXPECT_CALL(*mLifecycleManagerMock, IsAppLoaded(::testing::_, ::testing::_)) - .WillOnce([&](const std::string &appId, bool &loaded) { - loaded = false; - return Core::ERROR_GENERAL; - }); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->PreloadApp(APPMANAGER_APP_ID, APPMANAGER_APP_LAUNCHARGS, error)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for PreloadAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ -TEST_F(AppManagerTest, PreloadAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - std::string error = ""; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - ExpectedAppLifecycleEvent expectedEvent; - - createAppManagerImpl(); - - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = ""; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NOT_INSTALLED; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->PreloadApp(APPMANAGER_APP_ID, APPMANAGER_APP_LAUNCHARGS, error)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - releaseAppManagerImpl(); -} - -/* - * Test Case for CloseAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Setting Mock for OnAppLifecycleStateChanged() to simulate the app lifecycle state change - * Registering the notification handler to receive the app lifecycle state change event - * Simulating the app lifecycle state change event by calling OnAppLifecycleStateChanged() with expected parameters - * Waiting for the notification handler to receive the event and verifying the received event - * Verifying the received event matches the expected event - * Unregistering the notification handler - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, CloseAppUsingComRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = APPMANAGER_APP_INSTANCE; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - Plugin::AppManagerImplementation::AppInfo appInfo; - appInfo.appInstanceId = APPMANAGER_APP_INSTANCE; - appInfo.appNewState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - mAppManagerImpl->mAppInfo[APPMANAGER_APP_ID] = appInfo; - - /* Register the notification handler */ - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::PAUSED); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->CloseApp(APPMANAGER_APP_ID)); - // Simulate the app lifecycle state change event - mLifecycleManagerStateNotification_cb->OnAppLifecycleStateChanged( - APPMANAGER_APP_ID, - APPMANAGER_APP_INSTANCE, - Exchange::ILifecycleManager::LifecycleState::ACTIVE, // Old state - Exchange::ILifecycleManager::LifecycleState::PAUSED, // New state - "" - ); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for CloseAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Setting Mock for OnAppLifecycleStateChanged() to simulate the app lifecycle state change - * Registering the notification handler to receive the app lifecycle state change event - * Simulating the app lifecycle state change event by calling OnAppLifecycleStateChanged() with expected parameters - * Waiting for the notification handler to receive the event and verifying the received event - * Verifying the received event matches the expected event - * Unregistering the notification handler - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, CloseAppUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - - Plugin::AppManagerImplementation::AppInfo appInfo; - appInfo.appInstanceId = APPMANAGER_APP_INSTANCE; - appInfo.appNewState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - mAppManagerImpl->mAppInfo[APPMANAGER_APP_ID] = appInfo; - std::string requestClose = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - std::string requestLaunch = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + - "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + - "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("launchApp"), requestLaunch, mJsonRpcResponse)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - - // Simulate the app lifecycle state change event - EVENT_SUBSCRIBE(0, _T("onAppLifecycleStateChanged"), _T("org.rdk.AppManager"), message); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("closeApp"), requestClose, mJsonRpcResponse)); - Core::Event onAppLifecycleStateChanged(false, true); - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLifecycleStateChanged\",\"params\":{\"appId\":\"com.test.app\",\"appInstanceId\":\"testAppInstance\",\"newState\":\"APP_STATE_PAUSED\",\"oldState\":\"APP_STATE_ACTIVE\",\"errorReason\":\"APP_ERROR_NONE\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLifecycleStateChanged.SetEvent(); - return Core::ERROR_NONE; - })); - - ASSERT_NE(mLifecycleManagerStateNotification_cb, nullptr) - << "LifecycleManagerState notification callback is not registered"; - mLifecycleManagerStateNotification_cb->OnAppLifecycleStateChanged( - APPMANAGER_APP_ID, - APPMANAGER_APP_INSTANCE, - Exchange::ILifecycleManager::LifecycleState::ACTIVE, // Old state - Exchange::ILifecycleManager::LifecycleState::PAUSED, // New state - "" - ); - EXPECT_EQ(Core::ERROR_NONE, onAppLifecycleStateChanged.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLifecycleStateChanged"), _T("org.rdk.AppManager"), message); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for CloseAppUsingSuspendedStateCOMRPC - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the app in suspended state - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, CloseAppUsingComRpcSuspendedStateSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - Plugin::AppManagerImplementation::AppInfo appInfo; - appInfo.appInstanceId = APPMANAGER_APP_INSTANCE; - appInfo.appNewState = Exchange::IAppManager::AppLifecycleState::APP_STATE_PAUSED; - mAppManagerImpl->mAppInfo[APPMANAGER_APP_ID] = appInfo; - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::SUSPENDED); - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, struct stat* info) { - // Simulate a successful stat call - if (info != nullptr) { - info->st_mode = S_IFREG | 0644; // Regular file with read/write permissions - } - // Simulate success - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->CloseApp(APPMANAGER_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for CloseAppUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, CloseAppUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Sink notification; - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->CloseApp(APPMANAGER_WRONG_APP_ID)); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for CloseAppUsingComRpcFailureSetTargetAppStateReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate error return - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, CloseAppUsingComRpcFailureSetTargetAppStateReturnError) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Sink notification; - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - - EXPECT_CALL(*mLifecycleManagerMock, SetTargetAppState(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string& appInstanceId , const Exchange::ILifecycleManager::LifecycleState targetLifecycleState , const string& launchIntent) { - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->CloseApp(APPMANAGER_APP_ID)); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for CloseAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, CloseAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - createAppManagerImpl(); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->CloseApp(APPMANAGER_APP_ID)); - - releaseAppManagerImpl(); -} - -/* - * Test Case for TerminateAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Setting Mock for UnloadApp() to simulate unloading the app - * Setting Mock for Unlock() to simulate reset the lock flag - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, TerminateAppUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Sink notification; - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - UnloadAppAndUnlock(); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->TerminateApp(APPMANAGER_APP_ID)); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for TerminateAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Setting Mock for UnloadApp() to simulate unloading the app - * Setting Mock for Unlock() to simulate reset the lock flag - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, TerminateAppUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - std::string requestLaunch = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + - "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + - "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - } - )); - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("launchApp"), requestLaunch, mJsonRpcResponse)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - UnloadAppAndUnlock(); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("terminateApp"), request, mJsonRpcResponse)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for TerminateAppUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, TerminateAppUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->TerminateApp(APPMANAGER_WRONG_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for TerminateAppUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, TerminateAppUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->TerminateApp("")); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for TerminateAppUsingComRpcFailureUnloadAppReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Verifying the return of the API by no calling launch so that mInfo will be empty - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, TerminateAppUsingComRpcFailureUnloadAppReturnError) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->TerminateApp(APPMANAGER_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for TerminateAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, TerminateAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - createAppManagerImpl(); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->TerminateApp(APPMANAGER_APP_ID)); - releaseAppManagerImpl(); -} - -/* - * Test Case for StartSystemAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, StartSystemAppUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->StartSystemApp(APPMANAGER_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for StartSystemAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, StartSystemAppUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("startSystemApp"), request, mJsonRpcResponse)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for StopSystemAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, StopSystemAppUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->StopSystemApp(APPMANAGER_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for StopSystemAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, StopSystemAppUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("stopSystemApp"), request, mJsonRpcResponse)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for KillAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Setting Mock for UnloadApp() to simulate unloading the app - * Setting Mock for Unlock() to simulate reset the lock flag - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, KillAppUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Sink notification; - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - UnloadAppAndUnlock(); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->KillApp(APPMANAGER_APP_ID)); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* Test Case for KillAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Setting Mock for UnloadApp() to simulate unloading the app - * Setting Mock for Unlock() to simulate reset the lock flag - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, KillAppUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - std::string requestLaunch = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + - "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + - "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\"}"; - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - } - )); - - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("launchApp"), requestLaunch, mJsonRpcResponse)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("killApp"), request, mJsonRpcResponse)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for TerminateAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, KillAppUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->KillApp(APPMANAGER_WRONG_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for KillAppUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, KillAppUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->KillApp("")); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for KillAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, KillAppUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - createAppManagerImpl(); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->KillApp(APPMANAGER_WRONG_APP_ID)); - - releaseAppManagerImpl(); -} - -/* - * Test Case for SendIntentUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ - TEST_F(AppManagerTest, SendIntentUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Sink notification; - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.intent = APPMANAGER_APP_INTENT; - expectedEvent.source = ""; - - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - EXPECT_CALL(*mLifecycleManagerMock, SendIntentToActiveApp(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce([&](const string& appInstanceId, const string& intent, string& errorReason, bool& success) { - success = true; - return Core::ERROR_NONE; - }); - - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLaunchRequest); - EXPECT_TRUE(signalled & AppManager_onAppLaunchRequest); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->SendIntent(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT)); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SendIntentUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SendIntentUsingJSONRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - std::string requestLaunch = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + - "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + - "\", \"launchArgs\": \"" + std::string(APPMANAGER_APP_LAUNCHARGS) + "\"}"; - std::string requestintent = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\", \"intent\": \"" + std::string(APPMANAGER_APP_INTENT) + "\"}"; - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - } - )); - - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("launchApp"), requestLaunch, mJsonRpcResponse)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("sendIntent"), requestintent, mJsonRpcResponse)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SendIntentUsingComRpcFailureWrongAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the wrong app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SendIntentUsingComRpcFailureWrongAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SendIntent(APPMANAGER_WRONG_APP_ID, APPMANAGER_APP_INTENT)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SendIntentUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SendIntentUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SendIntent("", APPMANAGER_APP_INTENT)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SendIntentUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, SendIntentUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - createAppManagerImpl(); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SendIntent(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT)); - releaseAppManagerImpl(); -} - -/* - * Test Case for ClearAppDataUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, ClearAppDataUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mStorageManagerMock, Clear(::testing::_, ::testing::_)) - .WillOnce([&](const string& appId, const string& errorReason) { - return Core::ERROR_NONE; // Simulating successful clear of app data - }); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->ClearAppData(APPMANAGER_APP_ID)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for ClearAllAppDataUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, ClearAllAppDataUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mStorageManagerMock, ClearAll(::testing::_, ::testing::_)) - .WillOnce([&](const string& exemptionAppIds, const string& errorReason) { - return Core::ERROR_NONE; // Simulating successful clear of app data - }); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->ClearAllAppData()); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetAppMetadataUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppMetadataUsingComRpcSuccess) -{ - Core::hresult status; - const std::string dummymetaData = ""; - std::string dummyResult = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetAppMetadata(APPMANAGER_APP_ID, dummymetaData, dummyResult)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for GetAppMetadataUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppMetadataUsingJSONRpcSuccess) -{ - Core::hresult status; - const std::string dummymetaData = ""; - std::string dummyResult = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\", \"metadata\": \"" + dummymetaData + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getAppMetadata"), request, mJsonRpcResponse)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetAppPropertyUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for GetValue() to simulate getting value from persistent store - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppPropertyUsingComRpcSuccess) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mStore2Mock, GetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, ::testing::_, ::testing::_)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { - value = PERSISTENT_STORE_VALUE; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetAppProperty(APPMANAGER_APP_ID, key, value)); - EXPECT_STREQ(value.c_str(), PERSISTENT_STORE_VALUE); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for GetAppPropertyUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for GetValue() to simulate getting value from persistent store - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppPropertyUsingJSONRpcSuccess) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\", \"key\": \"" + key + "\"}"; - - EXPECT_CALL(*mStore2Mock, GetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, ::testing::_, ::testing::_)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { - value = PERSISTENT_STORE_VALUE; - return Core::ERROR_NONE; - }); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getAppProperty"), request, mJsonRpcResponse)); - EXPECT_STREQ(mJsonRpcResponse.c_str(), (std::string("\"") + PERSISTENT_STORE_VALUE + "\"").c_str()); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} -/* - * Test Case for GetAppPropertyUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppPropertyUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - const std::string key = ""; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetAppProperty(APPMANAGER_EMPTY_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetAppPropertyUsingComRpcFailureEmptyKey - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty key - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppPropertyUsingComRpcFailureEmptyKey) -{ - Core::hresult status; - const std::string key = ""; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetAppProperty(APPMANAGER_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetAppPropertyUsingComRpcFailureGetAppPropertyReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for GetValue() to simulate error return - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetAppPropertyUsingComRpcFailureGetAppPropertyReturnError) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mStore2Mock, GetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, ::testing::_, ::testing::_)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { - return Core::ERROR_GENERAL; - }); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetAppProperty(APPMANAGER_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetAppPropertyUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ - -TEST_F(AppManagerTest, GetAppPropertyUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - createAppManagerImpl(); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->GetAppProperty(APPMANAGER_APP_ID, key, value)); - releaseAppManagerImpl(); -} - -/* - * Test Case for SetAppPropertyUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for SetValue() to simulate setting value from persistent store - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SetAppPropertyUsingComRpcSuccess) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mStore2Mock, SetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, value, 0)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->SetAppProperty(APPMANAGER_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* Test Case for SetAppPropertyUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for SetValue() to simulate setting value from persistent store - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SetAppPropertyUsingJSONRpcSuccess) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{\"appId\": \"" + std::string(APPMANAGER_APP_ID) + "\", \"key\": \"" + key + "\", \"value\": \"" + value + "\"}"; - - EXPECT_CALL(*mStore2Mock, SetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, value, 0)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { - return Core::ERROR_NONE; - }); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("setAppProperty"), request, mJsonRpcResponse)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SetAppPropertyUsingComRpcFailureEmptyAppID - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty app id - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SetAppPropertyUsingComRpcFailureEmptyAppID) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SetAppProperty(APPMANAGER_EMPTY_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SetAppPropertyUsingComRpcFailureEmptyKey - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API by passing the empty key - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SetAppPropertyUsingComRpcFailureEmptyKey) -{ - Core::hresult status; - const std::string key = ""; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SetAppProperty(APPMANAGER_APP_ID, key, value)); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SetAppPropertyUsingComRpcFailureSetValueReturnError - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for SetValue() to simulate error return - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, SetAppPropertyUsingComRpcFailureSetValueReturnError) -{ - Core::hresult status; - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(*mStore2Mock, SetValue(Exchange::IStore2::ScopeType::DEVICE, APPMANAGER_APP_ID, key, value, 0)) - .WillOnce([&](const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { - return Core::ERROR_GENERAL; - }); - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SetAppProperty(APPMANAGER_APP_ID, key, value)); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for SetAppPropertyUsingComRpcFailureLifecycleManagerRemoteObjectIsNull - * Setting up only AppManager Plugin and creating required COM-RPC resources - * LifecycleManager Interface object is not created and hence the API should return error - * Verifying the return of the API - * Releasing the AppManager Interface object only - */ -TEST_F(AppManagerTest, SetAppPropertyUsingComRpcFailureLifecycleManagerRemoteObjectIsNull) -{ - const std::string key = PERSISTENT_STORE_KEY; - std::string value = ""; - - createAppManagerImpl(); - - EXPECT_EQ(Core::ERROR_GENERAL, mAppManagerImpl->SetAppProperty(APPMANAGER_APP_ID, key, value)); - - releaseAppManagerImpl(); -} - -/* - * Test Case for GetMaxRunningAppUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxRunningAppUsingComRpcSuccess) -{ - Core::hresult status; - int32_t maxRunningApps = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetMaxRunningApps(maxRunningApps)); - EXPECT_EQ(maxRunningApps, -1); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * GetMaxRunningAppUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxRunningAppUsingJSONRpcSuccess) -{ - Core::hresult status; - //int32_t maxRunningApps = 0; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getMaxRunningApps"), request, mJsonRpcResponse)); - EXPECT_EQ(mJsonRpcResponse, "-1"); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetMaxHibernatedAppsUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxHibernatedAppsUsingComRpcSuccess) -{ - Core::hresult status; - int32_t maxHibernatedApps = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetMaxHibernatedApps(maxHibernatedApps)); - EXPECT_EQ(maxHibernatedApps, -1); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * GetMaxHibernatedAppsUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxHibernatedAppsUsingJSONRpcSuccess) -{ - Core::hresult status; - //int32_t maxHibernatedApps = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - std::string request = "{}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getMaxHibernatedApps"), request, mJsonRpcResponse)); - EXPECT_EQ(mJsonRpcResponse, "-1"); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetMaxHibernatedFlashUsageUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxHibernatedFlashUsageUsingComRpcSuccess) -{ - Core::hresult status; - int32_t maxHibernatedFlashUsage = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetMaxHibernatedFlashUsage(maxHibernatedFlashUsage)); - EXPECT_EQ(maxHibernatedFlashUsage, -1); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* GetMaxHibernatedFlashUsageUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxHibernatedFlashUsageUsingJSONRpcSuccess) -{ - Core::hresult status; - //int32_t maxHibernatedFlashUsage = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getMaxHibernatedFlashUsage"), request, mJsonRpcResponse)); - EXPECT_EQ(std::stoi(mJsonRpcResponse), -1); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for GetMaxInactiveRamUsageUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxInactiveRamUsageUsingComRpcSuccess) -{ - Core::hresult status; - int32_t maxInactiveRamUsage = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetMaxInactiveRamUsage(maxInactiveRamUsage)); - EXPECT_EQ(maxInactiveRamUsage, -1); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * GetMaxInactiveRamUsageUsingJSONRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Implementation missing TODO: Testcase need to be added once implementation is done - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetMaxInactiveRamUsageUsingJSONRpcSuccess) -{ - Core::hresult status; - //int32_t maxInactiveRamUsage = 0; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::string request = "{}"; - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getMaxInactiveRamUsage"), request, mJsonRpcResponse)); - EXPECT_EQ(std::stoi(mJsonRpcResponse), -1); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for updateCurrentActionUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for ListPackages() to simulate getting installed package list - * Setting Mock for Lock() to simulate lockId and unpacked path - * Setting Mock for IsAppLoaded() to simulate the package is loaded or not - * Setting Mock for SetTargetAppState() to simulate setting the state - * Setting Mock for SpawnApp() to simulate spawning a app and gettign the appinstance id - * Calling LaunchApp first so that all the prerequisite will be filled - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, updateCurrentActionUsingComRpcSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - Core::Event onAppLaunchRequest(false, true); - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - std::string text; - EXPECT_TRUE(json->ToString(text)); - TEST_LOG("VEEKSHA - updateCurrentActionUsingComRpcSuccess - JSON-RPC response: %s", text.c_str()); - const std::string expectedJson = "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.AppManager.onAppLaunchRequest\",\"params\":{\"appId\":\"com.test.app\",\"intent\":\"test.intent\",\"source\":\"\"}}"; - EXPECT_EQ(text, expectedJson); - onAppLaunchRequest.SetEvent(); - return Core::ERROR_NONE; - } - )); - EVENT_SUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - LaunchAppPreRequisite(Exchange::ILifecycleManager::LifecycleState::ACTIVE); - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->LaunchApp(APPMANAGER_APP_ID, APPMANAGER_APP_INTENT, APPMANAGER_APP_LAUNCHARGS)); - EXPECT_EQ(Core::ERROR_NONE, onAppLaunchRequest.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppLaunchRequest"), _T("org.rdk.AppManager"), message); - - mAppManagerImpl->updateCurrentAction(APPMANAGER_APP_ID, Plugin::AppManagerImplementation::CurrentAction::APP_ACTION_LAUNCH); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* - * Test Case for updateCurrentActionUsingComRpcFailureAppIDNotExist - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Verifying the return of the API when app id doesn't exist - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, updateCurrentActionUsingComRpcFailureAppIDNotExist) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - - mAppManagerImpl->updateCurrentAction(APPMANAGER_APP_ID, Plugin::AppManagerImplementation::CurrentAction::APP_ACTION_LAUNCH); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for GetLoadedAppsJsonRpc - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required JSON-RPC resources - * Setting Mock for GetLoadedApps() to simulate getting loaded apps - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, GetLoadedAppsJsonRpc) -{ - Core::hresult status; - - status = createResources(); - Plugin::AppManagerImplementation::AppInfo appInfo; - Plugin::AppManagerImplementation::PackageInfo pkgInfo; - std::string nexTennisAppId = "NexTennis"; - appInfo.appInstanceId = nexTennisAppId; - pkgInfo.type = Plugin::AppManagerImplementation::ApplicationType::APPLICATION_TYPE_INTERACTIVE; - appInfo.packageInfo = pkgInfo; - mAppManagerImpl->mAppInfo[nexTennisAppId] = appInfo; - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mLifecycleManagerMock, GetLoadedApps(::testing::_, ::testing::_) - ).WillOnce([&](const bool verbose, std::string &apps) { - apps = R"([ - {"appId":"NexTennis","appInstanceID":"0295effd-2883-44ed-b614-471e3f682762","activeSessionId":"","targetLifecycleState":6,"lifecycleState":6}, - {"appId":"uktv","appInstanceID":"67fa75b6-0c85-43d4-a591-fd29e7214be5","activeSessionId":"","targetLifecycleState":6,"lifecycleState":6} - ])"; - return Core::ERROR_NONE; - }); - // Simulate a JSON-RPC call - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getLoadedApps"), _T("{}"), mJsonRpcResponse)); - EXPECT_STREQ(mJsonRpcResponse.c_str(), - "[{\"appId\":\"NexTennis\",\"appInstanceId\":\"0295effd-2883-44ed-b614-471e3f682762\",\"activeSessionId\":\"\",\"type\":\"INTERACTIVE_APP\",\"targetLifecycleState\":\"APP_STATE_HIBERNATED\",\"lifecycleState\":\"APP_STATE_HIBERNATED\"},{\"appId\":\"uktv\",\"appInstanceId\":\"67fa75b6-0c85-43d4-a591-fd29e7214be5\",\"activeSessionId\":\"\",\"type\":\"\",\"targetLifecycleState\":\"APP_STATE_HIBERNATED\",\"lifecycleState\":\"APP_STATE_HIBERNATED\"}]"); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for GetLoadedAppsCOMRPCSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PersistentStore/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Setting Mock for GetLoadedApps() to simulate getting loaded apps - * Verifying the return of the API - * Releasing the AppManager interface and all related test resources - */ -/* -TEST_F(AppManagerTest, GetLoadedAppsCOMRPCSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_CALL(*mLifecycleManagerMock, GetLoadedApps(::testing::_, ::testing::_) - ).WillOnce([&](const bool verbose, Exchange::IAppManager::ILoadedAppInfoIterator*& apps) { - auto mockIterator = FillLoadedAppsIterator(); // Fill the loaded apps - apps = mockIterator; - return Core::ERROR_NONE; - }); - std::string apps; - EXPECT_EQ(Core::ERROR_NONE, mAppManagerImpl->GetLoadedApps(apps)); - EXPECT_STREQ(apps.c_str(), - "[{\"appId\":\"NTV\",\"type\":\"\",\"appInstanceId\":\"0295effd-2883-44ed-b614-471e3f682762\",\"activeSessionId\":\"\",\"targetLifecycleState\":9,\"lifecycleState\":9}," - "{\"appId\":\"NexTennis\",\"type\":\"\",\"appInstanceId\":\"0295effd-2883-44ed-b614-471e3f682762\",\"activeSessionId\":\"\",\"targetLifecycleState\":8,\"lifecycleState\":8}," - "{\"appId\":\"uktv\",\"type\":\"\",\"appInstanceId\":\"67fa75b6-0c85-43d4-a591-fd29e7214be5\",\"activeSessionId\":\"\",\"targetLifecycleState\":7,\"lifecycleState\":7}," - "{\"appId\":\"YouTube\",\"type\":\"\",\"appInstanceId\":\"12345678-1234-1234-1234-123456789012\",\"activeSessionId\":\"\",\"targetLifecycleState\":6,\"lifecycleState\":6}," - "{\"appId\":\"Netflix\",\"type\":\"\",\"appInstanceId\":\"87654321-4321-4321-4321-210987654321\",\"activeSessionId\":\"\",\"targetLifecycleState\":4,\"lifecycleState\":4}," - "{\"appId\":\"Spotify\",\"type\":\"\",\"appInstanceId\":\"abcdefab-cdef-abcd-efab-cdefabcdefab\",\"activeSessionId\":\"\",\"targetLifecycleState\":3,\"lifecycleState\":3}," - "{\"appId\":\"Hulu\",\"type\":\"\",\"appInstanceId\":\"fedcbafe-dcba-fedc-ba98-7654321fedcb\",\"activeSessionId\":\"\",\"targetLifecycleState\":2,\"lifecycleState\":2}," - "{\"appId\":\"AmazonPrime\",\"type\":\"\",\"appInstanceId\":\"12345678-90ab-cdef-1234-567890abcdef\",\"activeSessionId\":\"\",\"targetLifecycleState\":1,\"lifecycleState\":1}]"); - - if(status == Core::ERROR_NONE) - { - releaseResources(); - } - -} -*/ -/* * Test Case for OnAppInstallationStatusChangedSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState/PackageManagerRDKEMS Plugin and creating required COM-RPC resources - * Registering the notification handler to receive the app installation status change event. - * Simulating the callback for app installation status change - * Wait for the notification to be signalled - * Verifying the return of the API - * Unregistering the notification - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, OnAppInstallationStatusChangedSuccess) -{ - Core::hresult status; - - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = "YouTube"; - expectedEvent.version = "100.1.30+rialto"; - Core::Sink notification; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - - ASSERT_NE(mPackageManagerNotification_cb, nullptr) << "PackageManager notification callback is not registered"; - mPackageManagerNotification_cb->OnAppInstallationStatus(TEST_JSON_INSTALLED_PACKAGE); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppInstalled); - EXPECT_TRUE(signalled & AppManager_onAppInstalled); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -/* * Test Case for OnApplicationStateChangedSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState Plugin and creating required COM-RPC resources - * Registering the notification handler to receive the application state change event. - * Simulating the callback for application state change - * Wait for the notification to be signalled - * Verifying the return of the API, ensuring that the OnAppLifecycleStateChanged callback is not called/invoked - * Unregistering the notification - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, OnApplicationStateChangedSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - uint32_t signalled = AppManager_StateInvalid; - Core::Sink notification; - mAppManagerImpl->Register(¬ification); - - ASSERT_NE(mLifecycleManagerStateNotification_cb, nullptr) - << "LifecycleManagerState notification callback is not registered"; - - mLifecycleManagerStateNotification_cb->OnAppLifecycleStateChanged( - "YouTube", - "12345678-1234-1234-1234-123456789012", - Exchange::ILifecycleManager::LifecycleState::ACTIVE, // Old state - Exchange::ILifecycleManager::LifecycleState::TERMINATING, // New state - "start" - ); - /* Ensure that the OnAppLifecycleStateChanged callback is not called/invoked */ - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_FALSE(signalled & AppManager_onAppLifecycleStateChanged); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) { - releaseResources(); - } -} - -/* - * Test Case for handleOnAppLifecycleStateChangedUsingComRpcSuccess - * Setting up AppManager/LifecycleManager/LifecycleManagerState Plugin and creating required COM-RPC Mock resources - * Registering the notification handler to receive the app lifecycle state change event. - * Simulating the callback for application lifecycle state change - * Wait for the notification to be signalled - * Verifying the return of the API - * Unregistering the notification - * Releasing the AppManager interface and all related test resources - */ -TEST_F(AppManagerTest, handleOnAppLifecycleStateChangedUsingComRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = APPMANAGER_APP_INSTANCE; - expectedEvent.oldState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED; - expectedEvent.newState = Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - expectedEvent.errorReason = Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE; - - /* Notification registration*/ - Core::Sink notification; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - mAppManagerImpl->handleOnAppLifecycleStateChanged( - APPMANAGER_APP_ID, - APPMANAGER_APP_INSTANCE, - Exchange::IAppManager::AppLifecycleState::APP_STATE_UNKNOWN, - Exchange::IAppManager::AppLifecycleState::APP_STATE_UNLOADED, - Exchange::IAppManager::AppErrorReason::APP_ERROR_NONE); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppLifecycleStateChanged); - EXPECT_TRUE(signalled & AppManager_onAppLifecycleStateChanged); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} - -TEST_F(AppManagerTest, handleOnAppUnloadedUsingComRpcSuccess) -{ - Core::hresult status; - status = createResources(); - EXPECT_EQ(Core::ERROR_NONE, status); - uint32_t signalled = AppManager_StateInvalid; - ExpectedAppLifecycleEvent expectedEvent; - expectedEvent.appId = APPMANAGER_APP_ID; - expectedEvent.appInstanceId = APPMANAGER_APP_INSTANCE; - - /* Notification registration*/ - Core::Sink notification; - mAppManagerImpl->Register(¬ification); - notification.SetExpectedEvent(expectedEvent); - mAppManagerImpl->handleOnAppUnloaded(APPMANAGER_APP_ID, APPMANAGER_APP_INSTANCE); - - signalled = notification.WaitForRequestStatus(TIMEOUT, AppManager_onAppUnloaded); - EXPECT_TRUE(signalled & AppManager_onAppUnloaded); - - mAppManagerImpl->Unregister(¬ification); - if(status == Core::ERROR_NONE) - { - releaseResources(); - } -} diff --git a/Tests/L1Tests/tests/test_DownloadManager.cpp b/Tests/L1Tests/tests/test_DownloadManager.cpp deleted file mode 100644 index 9cec0b7..0000000 --- a/Tests/L1Tests/tests/test_DownloadManager.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include -#include -#include -#include -#include -#include - -#include "DownloadManager.h" -#include "DownloadManagerImplementation.h" -#include -#include -using namespace WPEFramework; - -#include "ISubSystemMock.h" -#include "ServiceMock.h" -#include "COMLinkMock.h" -#include "ThunderPortability.h" -#include "WorkerPoolImplementation.h" -#include "FactoriesImplementation.h" - -#define TEST_LOG(x, ...) printf("[TEST_LOG] " x "\n", ##__VA_ARGS__) - -using ::testing::NiceMock; -using namespace std; - -typedef enum : uint32_t { - DownloadManager_invalidStatus = 0, - DownloadManager_AppDownloadStatus -} DownloadManagerTest_status_t; - -struct StatusParams { - string downloadId; - string fileLocator; - Exchange::IDownloadManager::FailReason reason; -}; - -class DownloadManagerTest : public ::testing::Test { -protected: - // Declare the protected members - ServiceMock* mServiceMock = nullptr; - SubSystemMock* mSubSystemMock = nullptr; - - Core::ProxyType workerPool; - Core::ProxyType plugin; - FactoriesImplementation factoriesImplementation; - - // Constructor - DownloadManagerTest() - : workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)), - plugin(Core::ProxyType::Create()) - { - if (workerPool.IsValid()) { - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - - if (!plugin.IsValid()) { - TEST_LOG("WARNING: Plugin creation failed - tests may be limited"); - } - } - - // Destructor - virtual ~DownloadManagerTest() override - { - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - } - - Core::hresult createResources() - { - Core::hresult status = Core::ERROR_GENERAL; - - try { - // Set up mocks and expect calls - mServiceMock = new NiceMock; - mSubSystemMock = new NiceMock; - - EXPECT_CALL(*mServiceMock, ConfigLine()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return("{\"downloadDir\": \"/opt/downloads/\"}")); - - EXPECT_CALL(*mServiceMock, PersistentPath()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return("/tmp/")); - - EXPECT_CALL(*mServiceMock, VolatilePath()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return("/tmp/")); - - EXPECT_CALL(*mServiceMock, DataPath()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return("/tmp/")); - - EXPECT_CALL(*mServiceMock, SubSystems()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return(mSubSystemMock)); - - EXPECT_CALL(*mServiceMock, AddRef()) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mServiceMock, Release()) - .Times(::testing::AnyNumber()); - - // Initialize plugin factories for L1 testing - PluginHost::IFactories::Assign(&factoriesImplementation); - - if (!plugin.IsValid()) { - return Core::ERROR_GENERAL; - } - status = Core::ERROR_NONE; - } catch (const std::exception& e) { - TEST_LOG("Exception in createResources: %s", e.what()); - status = Core::ERROR_GENERAL; - } catch (...) { - TEST_LOG("Unknown exception in createResources"); - status = Core::ERROR_GENERAL; - } - - return status; - } - - void releaseResources() - { - try { - if (mServiceMock) { - delete mServiceMock; - mServiceMock = nullptr; - } - - if (mSubSystemMock) { - delete mSubSystemMock; - mSubSystemMock = nullptr; - } - } catch (const std::exception& e) { - TEST_LOG("Exception in releaseResources: %s", e.what()); - } catch (...) { - TEST_LOG("Unknown exception in releaseResources"); - } - } - - void SetUp() override - { - try { - Core::hresult status = createResources(); - EXPECT_EQ(status, Core::ERROR_NONE); - } catch (const std::exception& e) { - TEST_LOG("Exception in SetUp: %s", e.what()); - FAIL() << "SetUp failed with exception: " << e.what(); - } catch (...) { - FAIL() << "SetUp failed with unknown exception"; - } - } - - void TearDown() override - { - releaseResources(); - } -}; - -class NotificationTest : public Exchange::IDownloadManager::INotification -{ - private: - mutable std::atomic m_refCount; - - public: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Status signal flag */ - uint32_t m_status_signal = DownloadManager_invalidStatus; - - StatusParams m_status_param; - - NotificationTest() : m_refCount(1) - { - } - - virtual ~NotificationTest() override = default; - - // Proper IUnknown implementation for Thunder framework - virtual void AddRef() const override { - m_refCount.fetch_add(1); - } - - virtual uint32_t Release() const override { - uint32_t result = m_refCount.fetch_sub(1) - 1; - if (result == 0) { - delete this; - } - return result; - } - - uint32_t WaitForStatusSignal(uint32_t timeout_ms, DownloadManagerTest_status_t status) - { - uint32_t status_signal = DownloadManager_invalidStatus; - std::unique_lock lock(m_mutex); - auto now = std::chrono::steady_clock::now(); - auto timeout = std::chrono::milliseconds(timeout_ms); - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - return m_status_signal; - } - status_signal = m_status_signal; - m_status_signal = DownloadManager_invalidStatus; - return status_signal; - } - private: - BEGIN_INTERFACE_MAP(NotificationTest) - INTERFACE_ENTRY(Exchange::IDownloadManager::INotification) - END_INTERFACE_MAP - - void SetStatusParams(const StatusParams& statusParam) - { - m_status_param = statusParam; - } - - void OnAppDownloadStatus(const string& downloadStatus) override { - m_status_signal = DownloadManager_AppDownloadStatus; - - std::unique_lock lock(m_mutex); - - JsonArray list; - list.FromString(downloadStatus); - - if (list.Length() > 0) { - JsonObject obj = list[0].Object(); - m_status_param.downloadId = obj["downloadId"].String(); - m_status_param.fileLocator = obj["fileLocator"].String(); - - if (obj.HasLabel("failReason")) { - string reason = obj["failReason"].String(); - if (reason == "DOWNLOAD_FAILURE") { - m_status_param.reason = Exchange::IDownloadManager::FailReason::DOWNLOAD_FAILURE; - } else if (reason == "DISK_PERSISTENCE_FAILURE") { - m_status_param.reason = Exchange::IDownloadManager::FailReason::DISK_PERSISTENCE_FAILURE; - } - } - } - - // Validate that JSON structure was properly parsed - EXPECT_TRUE(list.Length() > 0) << "JSON list should contain at least one element"; - if (list.Length() > 0) { - // Validate that downloadId field exists in JSON (even if empty) - JsonObject obj = list[0].Object(); - EXPECT_TRUE(obj.HasLabel("downloadId")) << "JSON should contain downloadId field"; - EXPECT_TRUE(obj.HasLabel("fileLocator")) << "JSON should contain fileLocator field"; - } - - m_condition_variable.notify_one(); - } - }; - -// Dedicated test fixture for DownloadManagerImplementation direct testing -class DownloadManagerImplementationTest : public ::testing::Test { -protected: - ServiceMock* mServiceMock = nullptr; - SubSystemMock* mSubSystemMock = nullptr; - Core::ProxyType mDownloadManagerImpl; - - DownloadManagerImplementationTest() { - // Create implementation object - mDownloadManagerImpl = Core::ProxyType::Create(); - } - - virtual ~DownloadManagerImplementationTest() override = default; - - void SetUp() override { - // Create mocks - mServiceMock = new NiceMock; - mSubSystemMock = new NiceMock; - - // Configure ServiceMock expectations for proper plugin operation - EXPECT_CALL(*mServiceMock, ConfigLine()) - .WillRepeatedly(::testing::Return("{\"downloadDir\":\"/tmp/downloads/\",\"downloadId\":3000}")); - - EXPECT_CALL(*mServiceMock, SubSystems()) - .WillRepeatedly(::testing::Return(mSubSystemMock)); - - EXPECT_CALL(*mServiceMock, AddRef()) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mServiceMock, Release()) - .Times(::testing::AnyNumber()); - - // Configure SubSystemMock - start with INTERNET active for successful downloads - EXPECT_CALL(*mSubSystemMock, IsActive(PluginHost::ISubSystem::INTERNET)) - .WillRepeatedly(::testing::Return(true)); - } - - void TearDown() override { - // Clean up implementation if initialized - if (mDownloadManagerImpl.IsValid()) { - // Deinitialize if it was initialized - mDownloadManagerImpl->Deinitialize(mServiceMock); - mDownloadManagerImpl.Release(); - } - - // Clean up mocks - if (mServiceMock) { - delete mServiceMock; - mServiceMock = nullptr; - } - - if (mSubSystemMock) { - delete mSubSystemMock; - mSubSystemMock = nullptr; - } - } - - Plugin::DownloadManagerImplementation* getRawImpl() { - if (mDownloadManagerImpl.IsValid()) { - return &(*mDownloadManagerImpl); - } - return nullptr; - } -}; - -/* Test Case for DownloadManagerImplementation - All IDownloadManager APIs with Plugin Lifecycle - * - * Test all IDownloadManager APIs with proper Initialize/Deinitialize cycle and plugin state management - * This test demonstrates complete plugin lifecycle and comprehensive API coverage - */ -TEST_F(DownloadManagerImplementationTest, AllIDownloadManagerAPIs) { - ASSERT_TRUE(mDownloadManagerImpl.IsValid()) << "DownloadManagerImplementation should be created successfully"; - Plugin::DownloadManagerImplementation* impl = getRawImpl(); - ASSERT_NE(impl, nullptr) << "Implementation pointer should be valid"; - - // === PHASE 1: PLUGIN INITIALIZATION === - // Initialize the plugin - this should succeed with proper mocks - Core::hresult initResult = impl->Initialize(mServiceMock); - EXPECT_EQ(Core::ERROR_NONE, initResult) << "Initialize should succeed with proper ServiceMock"; - - // Add small delay to ensure thread startup if initialization succeeded - if (initResult == Core::ERROR_NONE) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - // === PHASE 2: DOWNLOAD API TESTING === - Exchange::IDownloadManager::Options options; - options.priority = false; // Regular priority - options.retries = 3; // Retry attempts - options.rateLimit = 1024; // Rate limit in KB/s - - string downloadId; - - // Test successful download request (should succeed with INTERNET active) - Core::hresult downloadResult = impl->Download("http://example.com/test.zip", options, downloadId); - TEST_LOG("Download (valid URL) returned: %u, downloadId: %s", downloadResult, downloadId.c_str()); - EXPECT_EQ(Core::ERROR_NONE, downloadResult) << "Download should succeed with valid URL and active internet"; - EXPECT_FALSE(downloadId.empty()) << "Download should return valid downloadId"; - - // Test download with empty URL - should fail - string downloadId2; - Core::hresult downloadResult2 = impl->Download("", options, downloadId2); - TEST_LOG("Download (empty URL) returned: %u", downloadResult2); - EXPECT_NE(Core::ERROR_NONE, downloadResult2) << "Download should fail with empty URL"; - - // Test download without internet - temporarily disable internet subsystem - EXPECT_CALL(*mSubSystemMock, IsActive(PluginHost::ISubSystem::INTERNET)) - .WillOnce(::testing::Return(false)); - - string downloadId3; - Core::hresult downloadResult3 = impl->Download("http://example.com/test2.zip", options, downloadId3); - TEST_LOG("Download (no internet) returned: %u", downloadResult3); - EXPECT_EQ(Core::ERROR_UNAVAILABLE, downloadResult3) << "Download should fail when internet not available"; - EXPECT_TRUE(downloadId3.empty()) << "DownloadId should be empty on failure"; - - // Restore internet for remaining tests - EXPECT_CALL(*mSubSystemMock, IsActive(PluginHost::ISubSystem::INTERNET)) - .WillRepeatedly(::testing::Return(true)); - - // Test priority download - should succeed and return valid downloadId - Exchange::IDownloadManager::Options priorityOptions; - priorityOptions.priority = true; // High priority - priorityOptions.retries = 3; - priorityOptions.rateLimit = 1024; - - string priorityDownloadId; - Core::hresult priorityResult = impl->Download("http://example.com/priority.zip", priorityOptions, priorityDownloadId); - TEST_LOG("Download (priority) returned: %u, downloadId: %s", priorityResult, priorityDownloadId.c_str()); - EXPECT_EQ(Core::ERROR_NONE, priorityResult) << "Priority download should succeed"; - EXPECT_FALSE(priorityDownloadId.empty()) << "Priority download should return valid downloadId"; - - // Test regular download - should succeed and return different downloadId - string regularDownloadId; - Core::hresult regularResult = impl->Download("http://example.com/regular.zip", options, regularDownloadId); - TEST_LOG("Download (regular) returned: %u, downloadId: %s", regularResult, regularDownloadId.c_str()); - EXPECT_EQ(Core::ERROR_NONE, regularResult) << "Regular download should succeed"; - EXPECT_FALSE(regularDownloadId.empty()) << "Regular download should return valid downloadId"; - - // Verify downloadIds are different (incremented) - EXPECT_NE(priorityDownloadId, regularDownloadId) << "Each download should get unique downloadId"; - - // === PHASE 3: DOWNLOAD CONTROL APIS === - - // Test Pause with invalid ID - Core::hresult pauseResult = impl->Pause("invalid_download_id"); - TEST_LOG("Pause (invalid ID) returned: %u", pauseResult); - EXPECT_NE(Core::ERROR_NONE, pauseResult) << "Pause should fail with invalid downloadId"; - - // Test Pause with empty ID - Core::hresult pauseResult2 = impl->Pause(""); - TEST_LOG("Pause (empty ID) returned: %u", pauseResult2); - EXPECT_NE(Core::ERROR_NONE, pauseResult2) << "Pause should fail with empty downloadId"; - - // Test Resume with invalid ID - Core::hresult resumeResult = impl->Resume("invalid_download_id"); - TEST_LOG("Resume (invalid ID) returned: %u", resumeResult); - EXPECT_NE(Core::ERROR_NONE, resumeResult) << "Resume should fail with invalid downloadId"; - - // Test Resume with empty ID - Core::hresult resumeResult2 = impl->Resume(""); - TEST_LOG("Resume (empty ID) returned: %u", resumeResult2); - EXPECT_NE(Core::ERROR_NONE, resumeResult2) << "Resume should fail with empty downloadId"; - - // Test Cancel with invalid ID - Core::hresult cancelResult = impl->Cancel("invalid_download_id"); - TEST_LOG("Cancel (invalid ID) returned: %u", cancelResult); - EXPECT_NE(Core::ERROR_NONE, cancelResult) << "Cancel should fail with invalid downloadId"; - - // Test Cancel with empty ID - Core::hresult cancelResult2 = impl->Cancel(""); - TEST_LOG("Cancel (empty ID) returned: %u", cancelResult2); - EXPECT_NE(Core::ERROR_NONE, cancelResult2) << "Cancel should fail with empty downloadId"; - - // === PHASE 4: PROGRESS AND STATUS APIs === - - uint8_t percent = 0; - - // Test Progress with invalid ID - Core::hresult progressResult = impl->Progress("invalid_download_id", percent); - TEST_LOG("Progress (invalid ID) returned: %u, percent: %u", progressResult, percent); - EXPECT_NE(Core::ERROR_NONE, progressResult) << "Progress should fail with invalid downloadId"; - - // Test Progress with empty ID - Core::hresult progressResult2 = impl->Progress("", percent); - TEST_LOG("Progress (empty ID) returned: %u, percent: %u", progressResult2, percent); - EXPECT_NE(Core::ERROR_NONE, progressResult2) << "Progress should fail with empty downloadId"; - - // === PHASE 5: FILE MANAGEMENT APIS === - - // Test Delete with invalid file locator - Core::hresult deleteResult = impl->Delete("nonexistent_file.zip"); - TEST_LOG("Delete (invalid file) returned: %u", deleteResult); - EXPECT_NE(Core::ERROR_NONE, deleteResult) << "Delete should fail with nonexistent file"; - - // Test Delete with empty file locator - Core::hresult deleteResult2 = impl->Delete(""); - TEST_LOG("Delete (empty locator) returned: %u", deleteResult2); - EXPECT_NE(Core::ERROR_NONE, deleteResult2) << "Delete should fail with empty file locator"; - - // Test GetStorageDetails - should succeed (stub implementation) - uint32_t quotaKB = 0, usedKB = 0; - Core::hresult storageResult = impl->GetStorageDetails(quotaKB, usedKB); - TEST_LOG("GetStorageDetails returned: %u, quota: %u KB, used: %u KB", storageResult, quotaKB, usedKB); - EXPECT_EQ(Core::ERROR_NONE, storageResult) << "GetStorageDetails should succeed (stub implementation)"; - - // Test RateLimit API if it exists - additional coverage - if (!downloadId.empty()) { - Core::hresult rateLimitResult = impl->RateLimit(downloadId, 512); - TEST_LOG("RateLimit (valid ID, 512 KB/s) returned: %u", rateLimitResult); - // Don't assert on this as it depends on download state - - // Test RateLimit with invalid ID - Core::hresult rateLimitResult2 = impl->RateLimit("invalid_id", 1024); - TEST_LOG("RateLimit (invalid ID) returned: %u", rateLimitResult2); - EXPECT_NE(Core::ERROR_NONE, rateLimitResult2) << "RateLimit should fail with invalid downloadId"; - } - - // === PHASE 6: PLUGIN DEACTIVATION === - // Deinitialize will be called automatically in TearDown() -} - -/* Test Case: Plugin::DownloadManager APIs - * Tests plugin creation, Information API, and lifecycle methods - */ -TEST_F(DownloadManagerTest, PluginDownloadManagerAPIs) { - // Test plugin creation - ASSERT_TRUE(plugin.IsValid()) << "Plugin should be created successfully"; - - // Test interface inheritance - Plugin::DownloadManager* rawPlugin = &(*plugin); - ASSERT_NE(rawPlugin, nullptr) << "Raw plugin pointer should be valid"; - - PluginHost::JSONRPC* jsonrpcPtr = dynamic_cast(rawPlugin); - EXPECT_NE(jsonrpcPtr, nullptr) << "Plugin should inherit from PluginHost::JSONRPC"; - - PluginHost::IPlugin* pluginPtr = dynamic_cast(rawPlugin); - EXPECT_NE(pluginPtr, nullptr) << "Plugin should inherit from PluginHost::IPlugin"; - - // Test Information() API - should always return empty string - std::string infoResult = plugin->Information(); - EXPECT_TRUE(infoResult.empty()) << "Information() should always return empty string"; - - // Test Initialize() method - Returns string (empty = success, non-empty = error message) - std::string initResult = plugin->Initialize(mServiceMock); - bool initSucceeded = initResult.empty(); - - if (initSucceeded) { - TEST_LOG("Plugin Initialize: SUCCESS"); - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } else { - TEST_LOG("Plugin Initialize: FAILED (expected in L1) - %s", initResult.c_str()); - } - - // Test Deinitialize() method - returns void, should not crash - EXPECT_NO_THROW(plugin->Deinitialize(mServiceMock)) << "Deinitialize should not throw exceptions"; - - // Allow time for cleanup - std::this_thread::sleep_for(std::chrono::milliseconds(500)); -} \ No newline at end of file diff --git a/Tests/L1Tests/tests/test_LifecycleManager.cpp b/Tests/L1Tests/tests/test_LifecycleManager.cpp deleted file mode 100644 index 1d098d9..0000000 --- a/Tests/L1Tests/tests/test_LifecycleManager.cpp +++ /dev/null @@ -1,1502 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "LifecycleManager.h" -#include "LifecycleManagerImplementation.h" -#include "ServiceMock.h" -#include "RuntimeManagerMock.h" -#include "WindowManagerMock.h" -#include "WorkerPoolImplementation.h" - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define TIMEOUT (1000) - -typedef enum : uint32_t { - LifecycleManager_invalidEvent = 0, - LifecycleManager_onStateChangeEvent, - LifecycleManager_onRuntimeManagerEvent, - LifecycleManager_onWindowManagerEvent, - LifecycleManager_onRippleEvent -} LifecycleManagerTest_events_t; - -namespace WPEFramework { -namespace Plugin { -class LifecycleManagerImplementationTest : public LifecycleManagerImplementation { - public: - ApplicationContext* getContextImpl(const std::string& appInstanceId, const std::string& appId) const - { - return LifecycleManagerImplementation::getContext(appInstanceId, appId); - } -}; -} // namespace Plugin -} // namespace WPEFramework - -using ::testing::NiceMock; -using namespace WPEFramework; -using namespace std; - -class EventHandlerTest : public Plugin::IEventHandler { - public: - string appId; - string appInstanceId; - Exchange::ILifecycleManager::LifecycleState oldLifecycleState; - Exchange::ILifecycleManager::LifecycleState newLifecycleState; - Exchange::IRuntimeManager::RuntimeState state; - string navigationIntent; - string errorReason; - string name; - string errorCode; - string client; - vector runtimeEventName; - vector windowEventName; - double minutes; - - mutex m_mutex; - condition_variable m_condition_variable; - uint32_t m_event_signal = LifecycleManager_invalidEvent; - - void onStateChangeEvent(JsonObject& data) override - { - m_event_signal = LifecycleManager_onStateChangeEvent; - - EXPECT_EQ(appId, data["appId"].String()); - EXPECT_EQ(oldLifecycleState, static_cast(data["oldLifecycleState"].Number())); - EXPECT_EQ(newLifecycleState, static_cast(data["newLifecycleState"].Number())); - EXPECT_EQ(errorReason, data["errorReason"].String()); - - m_condition_variable.notify_one(); - } - - void onRuntimeManagerEvent(JsonObject& data) override - { - m_event_signal = LifecycleManager_onRuntimeManagerEvent; - - EXPECT_EQ(find(runtimeEventName.begin(), runtimeEventName.end(), data["name"].String()) != runtimeEventName.end(), true); - EXPECT_EQ(state, static_cast(data["state"].Number())); - EXPECT_EQ(errorCode, data["errorCode"].String()); - - m_condition_variable.notify_one(); - } - - void onWindowManagerEvent(JsonObject& data) override - { - m_event_signal = LifecycleManager_onWindowManagerEvent; - - EXPECT_EQ(find(windowEventName.begin(), windowEventName.end(), data["name"].String()) != windowEventName.end(), true); - EXPECT_EQ(client, data["client"].String()); - EXPECT_EQ(minutes, data["minutes"].Double()); - - m_condition_variable.notify_one(); - } - - void onRippleEvent(string name, JsonObject& data) override - { - m_event_signal = LifecycleManager_onRippleEvent; - - m_condition_variable.notify_one(); - } - - uint32_t WaitForEventStatus(uint32_t timeout_ms, LifecycleManagerTest_events_t status) - { - uint32_t event_signal = LifecycleManager_invalidEvent; - std::unique_lock lock(m_mutex); - auto now = std::chrono::steady_clock::now(); - auto timeout = std::chrono::milliseconds(timeout_ms); - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - return m_event_signal; - } - event_signal = m_event_signal; - m_event_signal = LifecycleManager_invalidEvent; - return event_signal; - } -}; - -class NotificationTest : public Exchange::ILifecycleManager::INotification -{ - private: - BEGIN_INTERFACE_MAP(NotificationTest) - INTERFACE_ENTRY(Exchange::ILifecycleManager::INotification) - END_INTERFACE_MAP - - public: - void OnAppStateChanged(const std::string& appId, Exchange::ILifecycleManager::LifecycleState state, const std::string& errorReason) override {} -}; - -class StateNotificationTest : public Exchange::ILifecycleManagerState::INotification -{ - private: - BEGIN_INTERFACE_MAP(StateNotificationTest) - INTERFACE_ENTRY(Exchange::ILifecycleManagerState::INotification) - END_INTERFACE_MAP - - public: - void OnAppLifecycleStateChanged(const std::string& appId, const std::string& appInstanceId, const Exchange::ILifecycleManager::LifecycleState oldState, const Exchange::ILifecycleManager::LifecycleState newState, const std::string& navigationIntent) override {} -}; - -class LifecycleManagerTest : public ::testing::Test { -protected: - string appId; - string launchIntent; - Exchange::ILifecycleManager::LifecycleState targetLifecycleState; - Exchange::RuntimeConfig runtimeConfigObject; - string launchArgs; - string appInstanceId; - string errorReason; - bool success; - vector runtimeEventName; - vector windowEventName; - string errorCode; - Exchange::IRuntimeManager::RuntimeState state; - string client; - double minutes; - - Core::ProxyType mLifecycleManagerImpl; - EventHandlerTest eventHdlTest; - Exchange::ILifecycleManager* interface = nullptr; - Exchange::ILifecycleManagerState* stateInterface = nullptr; - Exchange::IConfiguration* mLifecycleManagerConfigure = nullptr; - RuntimeManagerMock* mRuntimeManagerMock = nullptr; - WindowManagerMock* mWindowManagerMock = nullptr; - ServiceMock* mServiceMock = nullptr; - Core::ProxyType workerPool; - JsonObject eventData; - uint32_t event_signal; - - LifecycleManagerTest() - : workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)) - { - mLifecycleManagerImpl = Core::ProxyType::Create(); - - interface = static_cast(mLifecycleManagerImpl->QueryInterface(Exchange::ILifecycleManager::ID)); - - stateInterface = static_cast(mLifecycleManagerImpl->QueryInterface(Exchange::ILifecycleManagerState::ID)); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - - virtual ~LifecycleManagerTest() override - { - interface->Release(); - stateInterface->Release(); - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - } - - void createResources() - { - // Initialize the parameters with default values - appId = "com.test.app"; - launchIntent = "test.launch.intent"; - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::LOADING; - launchArgs = "test.arguments"; - appInstanceId = ""; - errorReason = ""; - success = true; - runtimeEventName = {"onTerminated", "onStateChanged", "onFailure", "onStarted"}; - windowEventName = {"onReady", "onDisconnect", "onUserInactivity"}; - errorCode = "1"; - state = Exchange::IRuntimeManager::RuntimeState::RUNTIME_STATE_SUSPENDED; - client = "test.client"; - minutes = 24; - - runtimeConfigObject = { - true,true,true,1024,512,"test.env.variables",1,1,1024,true,"test.dial.id","test.command","test.app.type","test.app.path","test.runtime.path","test.logfile.path",1024,"test.log.levels",true,"test.fkps.files","test.firebolt.version",true,"test.unpacked.path" - }; - - // Initialize event parameters and event data - eventHdlTest.appId = appId; - eventHdlTest.appInstanceId = appInstanceId; - eventHdlTest.oldLifecycleState = Exchange::ILifecycleManager::LifecycleState::UNLOADED; - eventHdlTest.newLifecycleState = targetLifecycleState; - eventHdlTest.errorReason = errorReason; - eventHdlTest.state = state; - eventHdlTest.errorCode = errorCode; - eventHdlTest.client = client; - eventHdlTest.minutes = minutes; - eventHdlTest.runtimeEventName = runtimeEventName; - eventHdlTest.windowEventName = windowEventName; - - eventData["appId"] = appId; - eventData["appInstanceId"] = appInstanceId; - eventData["oldLifecycleState"] = static_cast(Exchange::ILifecycleManager::LifecycleState::UNLOADED); - eventData["newLifecycleState"] = static_cast(targetLifecycleState); - eventData["navigationIntent"] = launchIntent; - eventData["errorReason"] = errorReason; - eventData["name"] = ""; - eventData["state"] = static_cast(state); - eventData["errorCode"] = errorCode; - eventData["client"] = client; - eventData["minutes"] = minutes; - - event_signal = LifecycleManager_invalidEvent; - - // Set up mocks and expect calls - mServiceMock = new NiceMock; - mRuntimeManagerMock = new NiceMock; - mWindowManagerMock = new NiceMock; - - mLifecycleManagerConfigure = static_cast(mLifecycleManagerImpl->QueryInterface(Exchange::IConfiguration::ID)); - - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t, const std::string& name) -> void* { - if (name == "org.rdk.RuntimeManager") { - return reinterpret_cast(mRuntimeManagerMock); - } else if (name == "org.rdk.RDKWindowManager") { - return reinterpret_cast(mWindowManagerMock); - } - return nullptr; - })); - - EXPECT_CALL(*mServiceMock, AddRef()) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mRuntimeManagerMock, Register(::testing::_)) - .WillRepeatedly(::testing::Return(Core::ERROR_NONE)); - - EXPECT_CALL(*mWindowManagerMock, Register(::testing::_)) - .WillRepeatedly(::testing::Return(Core::ERROR_NONE)); - - // Configure the LifecycleManager - mLifecycleManagerConfigure->Configure(mServiceMock); - - ASSERT_TRUE(interface != nullptr); - } - - void releaseResources() - { - // Clean up mocks - if (mServiceMock != nullptr) - { - EXPECT_CALL(*mServiceMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mServiceMock; - mServiceMock = nullptr; - return 0; - })); - } - - if (mRuntimeManagerMock != nullptr) - { - EXPECT_CALL(*mRuntimeManagerMock, Unregister(::testing::_)) - .WillRepeatedly(::testing::Return(Core::ERROR_NONE)); - - EXPECT_CALL(*mRuntimeManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mRuntimeManagerMock; - mRuntimeManagerMock = nullptr; - return 0; - })); - } - - if (mWindowManagerMock != nullptr) - { - EXPECT_CALL(*mWindowManagerMock, Unregister(::testing::_)) - .WillRepeatedly(::testing::Return(Core::ERROR_NONE)); - - EXPECT_CALL(*mWindowManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mWindowManagerMock; - mWindowManagerMock = nullptr; - return 0; - })); - } - - // Clean up the LifecycleManager - mLifecycleManagerConfigure->Release(); - - ASSERT_TRUE(interface != nullptr); - } - - void onStateChangeEventSignal() - { - event_signal = LifecycleManager_invalidEvent; - - eventHdlTest.onStateChangeEvent(eventData); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onStateChangeEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onStateChangeEvent); - } - - void onRuntimeManagerEventSignal(JsonObject data) - { - eventData["name"] = data["name"]; - - event_signal = LifecycleManager_invalidEvent; - - eventHdlTest.onRuntimeManagerEvent(eventData); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onRuntimeManagerEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onRuntimeManagerEvent); - } - - void onWindowManagerEventSignal(JsonObject data) - { - eventData["name"] = data["name"]; - - event_signal = LifecycleManager_invalidEvent; - - eventHdlTest.onWindowManagerEvent(eventData); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onWindowManagerEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onWindowManagerEvent); - } -}; - -/* Test Case for Registering and Unregistering Notification - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Create a notification instance using the NotificationTest class - * Register the notification with the Lifecycle Manager interface - * Verify successful registration of notification by asserting that Register() returns Core::ERROR_NONE - * Unregister the notification from the Lifecycle Manager interface - * Verify successful unregistration of notification by asserting that Unregister() returns Core::ERROR_NONE - * Release the Lifecycle Manager interface object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unregisterNotification_afterRegister) -{ - createResources(); - - Core::Sink notification; - - // TC-1: Check if the notification is unregistered after registering - EXPECT_EQ(Core::ERROR_NONE, interface->Register(¬ification)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Unregister(¬ification)); - - releaseResources(); -} - -/* Test Case for Unregistering Notification without registering - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Create a notification instance using the NotificationTest class - * Unregister the notification from the Lifecycle Manager interface - * Verify unregistration of notification fails by asserting that Unregister() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager interface object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unregisterNotification_withoutRegister) -{ - createResources(); - - Core::Sink notification; - - // TC-2: Check if the notification is unregistered without registering - EXPECT_EQ(Core::ERROR_GENERAL, interface->Unregister(¬ification)); - - releaseResources(); -} - -/* Test Case for Registering and Unregistering State Notification - * - * Set up Lifecycle Manager state interface, configurations, required COM-RPC resources, mocks and expectations - * Create a state notification instance using the StateNotificationTest class - * Register the state notification with the Lifecycle Manager state interface - * Verify successful registration of state notification by asserting that Register() returns Core::ERROR_NONE - * Unregister the state notification from the Lifecycle Manager state interface - * Verify successful unregistration of state notification by asserting that Unregister() returns Core::ERROR_NONE - * Release the Lifecycle Manager state interface object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unregisterStateNotification_afterRegister) -{ - createResources(); - - Core::Sink stateNotification; - - // TC-3: Check if the state notification is registered after unregistering - EXPECT_EQ(Core::ERROR_NONE, stateInterface->Register(&stateNotification)); - - EXPECT_EQ(Core::ERROR_NONE, stateInterface->Unregister(&stateNotification)); - - releaseResources(); -} - -/* Test Case for Unregistering State Notification without registering - * - * Set up Lifecycle Manager state interface, configurations, required COM-RPC resources, mocks and expectations - * Create a state notification instance using the StateNotificationTest class - * Unregister the state notification from the Lifecycle Manager state interface - * Verify unregistration of state notification fails by asserting that Unregister() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager state interface object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unregisterStateNotification_withoutRegister) -{ - createResources(); - - Core::Sink stateNotification; - - // TC-4: Check if the state notification is registered without unregistering - EXPECT_EQ(Core::ERROR_GENERAL, stateInterface->Unregister(&stateNotification)); - - releaseResources(); -} - -/* Test Case for Spawning an App - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeonStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, spawnApp_withValidParams) -{ - createResources(); - - // TC-5: Spawn an app with all parameters valid - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for App Ready after Spawning - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING. - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Check if the app is ready after spawning with the appId - * Verify that the app is ready by asserting that AppReady() returns Core::ERROR_NONE - * Obtain the loaded app context using getContextImpl() and wait for the app ready semaphore - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, appready_onSpawnAppSuccess) -{ - createResources(); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-6: Check if app is ready after spawning - EXPECT_EQ(Core::ERROR_NONE, stateInterface->AppReady(appId)); - - Plugin::ApplicationContext* context = mLifecycleManagerImpl->getContextImpl("", appId); - - sem_wait(&context->mAppReadySemaphore); - - releaseResources(); -} - -/* Test Case for App Ready with invalid AppId after Spawning - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Check failure of app ready due to invalid appId by asserting that AppReady() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, appready_oninvalidAppId) -{ - createResources(); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-7: Verify error on passing an invalid appId - EXPECT_EQ(Core::ERROR_GENERAL, stateInterface->AppReady("")); - - releaseResources(); -} - -/* Test Case for querying if App is Loaded after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Check if the app is loaded after spawning with the appId - * Verify that the app is loaded by asserting that IsAppLoaded() returns Core::ERROR_NONE - * Check that the loaded flag is set to true, confirming that the app is loaded - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, isAppLoaded_onSpawnAppSuccess) -{ - createResources(); - - bool loaded = false; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-8: Check if app is loaded after spawning - EXPECT_EQ(Core::ERROR_NONE, interface->IsAppLoaded(appId, loaded)); - - EXPECT_EQ(loaded, true); - - releaseResources(); -} - -/* Test Case for querying if App is Loaded with invalid AppId after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Check failure of app loaded due to invalid appId by asserting that IsAppLoaded() returns Core::ERROR_GENERAL - * Check that the loaded flag is set to false, confirming that the app is not loaded - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, isAppLoaded_oninvalidAppId) -{ - createResources(); - - bool loaded = true; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-9: Verify error on passing an invalid appId - EXPECT_EQ(Core::ERROR_NONE, interface->IsAppLoaded("", loaded)); - - EXPECT_EQ(loaded, false); - - releaseResources(); -} - -/* Test Case for getLoadedApps with verbose enabled after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Enable the verbose flag by setting it to true - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Obtain the loaded apps and assert that GetLoadedApps() returns Core::ERROR_NONE - * Verify the app list parameters by comparing the obtained and expected appId - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, getLoadedApps_verboseEnabled) -{ - createResources(); - - bool verbose = true; - string apps = ""; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-10: Get loaded apps with verbose enabled - EXPECT_EQ(Core::ERROR_NONE, interface->GetLoadedApps(verbose, apps)); - - EXPECT_THAT(apps, ::testing::HasSubstr("\"appId\":\"com.test.app\"")); - - releaseResources(); -} - -/* Test Case for getLoadedApps with verbose disabled after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Disable the verbose flag by setting it to false - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Obtain the loaded apps and assert that GetLoadedApps() returns Core::ERROR_NONE - * Verify the app list parameters by comparing the obtained and expected app list - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, getLoadedApps_verboseDisabled) -{ - createResources(); - - bool verbose = false; - string apps = ""; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-11: Get loaded apps with verbose disabled - EXPECT_EQ(Core::ERROR_NONE, interface->GetLoadedApps(verbose, apps)); - - EXPECT_THAT(apps, ::testing::HasSubstr("\"appId\":\"com.test.app\"")); - - releaseResources(); -} - -/* Test Case for getLoadedApps with verbose enabled without Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Enable the verbose flag by setting it to true - * Obtain the loaded apps and assert that GetLoadedApps() returns Core::ERROR_NONE - * Verify the app list parameters is empty indicating no apps are loaded - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, getLoadedApps_noAppsLoaded) -{ - createResources(); - - bool verbose = true; - string apps = ""; - - // TC-12: Check that no apps are loaded - EXPECT_EQ(Core::ERROR_NONE, interface->GetLoadedApps(verbose, apps)); - - EXPECT_EQ(apps, "[]"); - - releaseResources(); -} - -/* Test Case for setTargetAppState with valid parameters - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Set the target state of the app from LOADING to ACTIVE with valid parameters - * Verify successful state change by asserting that SetTargetAppState() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Repeat the same process with only required parameters valid - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, setTargetAppState_withValidParams) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - // TC-13: Set the target state of a loaded app with all parameters valid - EXPECT_EQ(Core::ERROR_NONE, interface->SetTargetAppState(appInstanceId, targetLifecycleState, launchIntent)); - - onStateChangeEventSignal(); - - // TC-14: Set the target state of a loaded app with only required parameters valid - EXPECT_EQ(Core::ERROR_NONE, interface->SetTargetAppState(appInstanceId, targetLifecycleState, "")); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for setTargetAppState with invalid parameters - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Set the target state of the app to LOADING with invalid appInstanceId - * Verify state change fails by asserting that SetTargetAppState() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, setTargetAppState_withinvalidParams) -{ - createResources(); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-15: Set the target state of a loaded app with invalid appInstanceId - EXPECT_EQ(Core::ERROR_GENERAL, interface->SetTargetAppState("", targetLifecycleState, launchIntent)); - - releaseResources(); -} - -/* Test Case for Unload App after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Unload the app using the appInstanceId - * Verify that app is successfully unloaded by asserting that UnloadApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unloadApp_onSpawnAppSuccess) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Terminate(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-16: Unload the app after spawning - EXPECT_EQ(Core::ERROR_NONE, interface->UnloadApp(appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Unload App without Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Set the appInstanceId to a random test value - * Unload the app using the appInstanceId - * Verify failure of app unload by asserting that UnloadApp() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, unloadApp_withoutSpawning) -{ - createResources(); - - appInstanceId = "test.app.instance"; - - // TC-17: Unload the app after spawn fails - EXPECT_EQ(Core::ERROR_GENERAL, interface->UnloadApp(appInstanceId, errorReason, success)); - - releaseResources(); -} - -/* Test Case for Kill App after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Kill the app using the appInstanceId - * Verify that app is successfully killed by asserting that KillApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, killApp_onSpawnAppSuccess) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Kill(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-18: Kill the app after spawning - EXPECT_EQ(Core::ERROR_NONE, interface->KillApp(appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Kill App without Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Set the appInstanceId to a random test value - * Kill the app using the appInstanceId - * Verify failure of app kill by asserting that KillApp() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager interface object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, killApp_withoutSpawning) -{ - createResources(); - - appInstanceId = "test.app.instance"; - - // TC-19: Kill the app after spawn fails - EXPECT_EQ(Core::ERROR_GENERAL, interface->KillApp(appInstanceId, errorReason, success)); - - releaseResources(); -} - -/* Test Case for Close App on User Exit - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Close the app using the appId and setting the reason for close as USER EXIT - * Verify that app is successfully closed by asserting that CloseApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, closeApp_onUserExit) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Kill(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-20: User exits the app after spawning - EXPECT_EQ(Core::ERROR_NONE, stateInterface->CloseApp(appId, Exchange::ILifecycleManagerState::AppCloseReason::USER_EXIT)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Close App on Error - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Close the app using the appId and setting the reason for close as ERROR - * Verify that app is successfully closed by asserting that CloseApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, closeApp_onError) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Kill(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-21: Error after spawning the app - EXPECT_EQ(Core::ERROR_NONE, stateInterface->CloseApp(appId, Exchange::ILifecycleManagerState::AppCloseReason::ERROR)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Close App on Kill and Run - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Close the app using the appId and setting the reason for close as KILL AND RUN - * Verify that app is successfully closed by asserting that CloseApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, closeApp_onKillandRun) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Kill(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-22: Kill and run after spawning the app - EXPECT_EQ(Core::ERROR_NONE, stateInterface->CloseApp(appId, Exchange::ILifecycleManagerState::AppCloseReason::KILL_AND_RUN)); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onStateChangeEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onStateChangeEvent); - - onStateChangeEventSignal(); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onStateChangeEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onStateChangeEvent); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Close App on Kill and Activate - * - * Set up Lifecycle Manager interface, state interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as LOADING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Close the app using the appId and setting the reason for close as KILL AND ACTIVATE - * Verify that app is successfully closed by asserting that CloseApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, closeApp_onKillandActivate) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Kill(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-23: Kill and activate after spawning the app - EXPECT_EQ(Core::ERROR_NONE, stateInterface->CloseApp(appId, Exchange::ILifecycleManagerState::AppCloseReason::KILL_AND_ACTIVATE)); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onStateChangeEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onStateChangeEvent); - - onStateChangeEventSignal(); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onStateChangeEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onStateChangeEvent); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for State Change Complete with valid parameters - * - * Set up Lifecycle Manager state interface, configurations, required COM-RPC resources, mocks and expectations - * Set the stateChangedId to a random test value - * Signal that the state change is complete - * Verify successful state change by asserting that StateChangeComplete() returns Core::ERROR_NONE - * Release the Lifecycle Manager state object and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, stateChangeComplete_withValidParams) -{ - createResources(); - - uint32_t stateChangedId = 1; - - // TC-24: Check if state change is complete - EXPECT_EQ(Core::ERROR_NONE, stateInterface->StateChangeComplete(appId, stateChangedId, success)); - - releaseResources(); -} - -/* Test Case for Send Intent to Active App after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Set the intent to a random test value - * Spawn an app with valid parameters with target state as ACTIVE - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Send an intent to the active app using the appInstanceId - * Verify failure of sent intent (due to failure in websocket) by asserting that SendIntentToActiveApp() returns Core::ERROR_GENERAL - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, sendIntenttoActiveApp_onSpawnAppSuccess) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - string intent = "test.intent"; - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - // TC-25: Send intent to the app after spawning - EXPECT_EQ(Core::ERROR_GENERAL, interface->SendIntentToActiveApp(appInstanceId, intent, errorReason, success)); - - onStateChangeEventSignal(); - - releaseResources(); -} - -/* Test Case for Runtime Manager Event - onTerminated after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as ACTIVE - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Terminate the app with the appInstanceId - * Verify successful termination by asserting that UnloadApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onTerminated along with the appInstanceId obtained - * Signal the Runtime Manager Event using onRuntimeManagerEvent() with the data - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, runtimeManagerEvent_onTerminated) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mRuntimeManagerMock, Terminate(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appInstanceId) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - EXPECT_EQ(Core::ERROR_NONE, interface->UnloadApp(appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onTerminated"; - data["appInstanceId"] = appInstanceId; - - // TC-26: Signal the Runtime Manager Event - onTerminated - mLifecycleManagerImpl->onRuntimeManagerEvent(data); - - onRuntimeManagerEventSignal(data); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onRuntimeManagerEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onRuntimeManagerEvent); - - releaseResources(); -} - -/* Test Case for Runtime Manager Event - onStateChanged after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as INITIALIZING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onStateChanged along with the state as SUSPENDED and appInstanceId obtained - * Signal the Runtime Manager Event using onRuntimeManagerEvent() with the data - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, runtimeManagerEvent_onStateChanged) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::INITIALIZING; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onStateChanged"; - data["appInstanceId"] = appInstanceId; - data["state"] = 3; - - // TC-27: Signal the Runtime Manager Event - onStateChanged - mLifecycleManagerImpl->onRuntimeManagerEvent(data); - - onRuntimeManagerEventSignal(data); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onRuntimeManagerEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onRuntimeManagerEvent); - - releaseResources(); -} - -/* Test Case for Runtime Manager Event - onFailure after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as INITIALIZING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onFailure along with the error code and appInstanceId obtained - * Signal the Runtime Manager Event using onRuntimeManagerEvent() with the data - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, runtimeManagerEvent_onFailure) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::INITIALIZING; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onFailure"; - data["appInstanceId"] = appInstanceId; - data["errorCode"] = 1; - - // TC-28: Signal the Runtime Manager Event - onFailure - mLifecycleManagerImpl->onRuntimeManagerEvent(data); - - onRuntimeManagerEventSignal(data); - - releaseResources(); -} - -/* Test Case for Runtime Manager Event - onStarted after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as INITIALIZING - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onStarted along with the appInstanceId obtained - * Signal the Runtime Manager Event using onRuntimeManagerEvent() with the data - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, runtimeManagerEvent_onStarted) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::INITIALIZING; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onStarted"; - data["appInstanceId"] = appInstanceId; - - // TC-29: Signal the Runtime Manager Event - onStarted - mLifecycleManagerImpl->onRuntimeManagerEvent(data); - - onRuntimeManagerEventSignal(data); - - releaseResources(); -} - -/* Test Case for Window Manager Event - onUserInactivity after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as ACTIVE - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onUserInactivity - * Signal the Window Manager Event using onWindowManagerEvent() with the data - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, windowManagerEvent_onUserInactivity) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onUserInactivity"; - data["minutes"] = 24; - - // TC-30: Signal the Window Manager Event - onUserInactivity - mLifecycleManagerImpl->onWindowManagerEvent(data); - - onWindowManagerEventSignal(data); - - releaseResources(); -} - -/* Test Case for Window Manager Event - onDisconnect after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as ACTIVE - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onDisconnect - * Signal the Window Manager Event using onWindowManagerEvent() with the data - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, windowManagerEvent_onDisconnect) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onDisconnect"; - data["client"] = "test.client"; - - // TC-31: Signal the Window Manager Event - onDisconnect - mLifecycleManagerImpl->onWindowManagerEvent(data); - - onWindowManagerEventSignal(data); - - releaseResources(); -} - -/* Test Case for Window Manager Event - onReady after Spawning - * - * Set up Lifecycle Manager interface, configurations, required COM-RPC resources, mocks and expectations - * Spawn an app with valid parameters with target state as ACTIVE - * Verify successful spawn by asserting that SpawnApp() returns Core::ERROR_NONE - * Handle event signals by calling the onStateChangeEventSignal() method - * Populate the data by setting the event name as onReady along with the appInstanceId obtained - * Signal the Window Manager Event using onWindowManagerEvent() with the data - * Handle event signals by calling the onStateChangeEventSignal() method - * Release the Lifecycle Manager objects and clean-up related test resources - */ - -TEST_F(LifecycleManagerTest, windowManagerEvent_onReady) -{ - createResources(); - - EXPECT_CALL(*mRuntimeManagerMock, Run(appId, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const string& appInstanceId, const uint32_t userId, const uint32_t groupId, Exchange::IRuntimeManager::IValueIterator* const& ports, Exchange::IRuntimeManager::IStringIterator* const& paths, Exchange::IRuntimeManager::IStringIterator* const& debugSettings, const Exchange::RuntimeConfig& runtimeConfigObject) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mWindowManagerMock, RenderReady(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& client, bool &status) { - return Core::ERROR_NONE; - })); - - targetLifecycleState = Exchange::ILifecycleManager::LifecycleState::ACTIVE; - - EXPECT_EQ(Core::ERROR_NONE, interface->SpawnApp(appId, launchIntent, targetLifecycleState, runtimeConfigObject, launchArgs, appInstanceId, errorReason, success)); - - onStateChangeEventSignal(); - - JsonObject data; - - data["name"] = "onReady"; - data["appInstanceId"] = appInstanceId; - - // TC-32: Signal the Window Manager Event - onReady - mLifecycleManagerImpl->onWindowManagerEvent(data); - - onWindowManagerEventSignal(data); - - event_signal = eventHdlTest.WaitForEventStatus(TIMEOUT, LifecycleManager_onWindowManagerEvent); - - EXPECT_TRUE(event_signal & LifecycleManager_onWindowManagerEvent); - - releaseResources(); -} diff --git a/Tests/L1Tests/tests/test_MessageControl.cpp b/Tests/L1Tests/tests/test_MessageControl.cpp deleted file mode 100644 index dd534ad..0000000 --- a/Tests/L1Tests/tests/test_MessageControl.cpp +++ /dev/null @@ -1,540 +0,0 @@ -#include -#include -#include "MessageControl.h" -#include -#include -#include -#include -#include - -using namespace WPEFramework; -using namespace WPEFramework::Plugin; - -class MessageControlL1Test : public ::testing::Test { -protected: - Core::ProxyType plugin; - PluginHost::IShell* _shell; - bool _shellOwned; - - void SetUp() override { - plugin = Core::ProxyType::Create(); - _shell = nullptr; - _shellOwned = false; - } - - void TearDown() override { - if (_shell != nullptr) { - if (plugin.IsValid()) { - plugin->Deinitialize(_shell); - } - if (_shellOwned) { - delete _shell; - } - _shell = nullptr; - _shellOwned = false; - } - plugin.Release(); - } - - class TestShell : public PluginHost::IShell { - public: - explicit TestShell(const string& config = R"({"console":true,"syslog":false})") - : _config(config) - , _refCount(1) - { - } - - string ConfigLine() const override { - return _config; - } - string VolatilePath() const override { return "/tmp/"; } - bool Background() const override { return false; } - string Accessor() const override { return ""; } - string WebPrefix() const override { return ""; } - string Callsign() const override { return "MessageControl"; } - string HashKey() const override { return ""; } - string PersistentPath() const override { return "/tmp/"; } - string DataPath() const override { return "/tmp/"; } - string ProxyStubPath() const override { return "/tmp/"; } - string SystemPath() const override { return "/tmp/"; } - string PluginPath() const override { return "/tmp/"; } - string SystemRootPath() const override { return "/tmp/"; } - string Locator() const override { return ""; } - string ClassName() const override { return ""; } - string Versions() const override { return ""; } - string Model() const override { return ""; } - - state State() const override { return state::ACTIVATED; } - bool Resumed() const override { return true; } - Core::hresult Resumed(const bool) override { return Core::ERROR_NONE; } - reason Reason() const override { return reason::REQUESTED; } - - PluginHost::ISubSystem* SubSystems() override { return nullptr; } - startup Startup() const override { return startup::ACTIVATED; } - Core::hresult Startup(const startup) override { return Core::ERROR_NONE; } - ICOMLink* COMLink() override { return nullptr; } - void* QueryInterface(const uint32_t) override { return nullptr; } - - void AddRef() const override { - Core::InterlockedIncrement(_refCount); - } - - uint32_t Release() const override { - return Core::InterlockedDecrement(_refCount); - } - - void EnableWebServer(const string& URLPath, const string& fileSystemPath) override {} - void DisableWebServer() override {} - Core::hresult SystemRootPath(const string& systemRootPath) override { return Core::ERROR_NONE; } - string Substitute(const string& input) const override { return input; } - Core::hresult ConfigLine(const string& config) override { return Core::ERROR_NONE; } - Core::hresult Metadata(string& info) const override { return Core::ERROR_NONE; } - bool IsSupported(const uint8_t version) const override { return true; } - void Notify(const string& message) override {} - void Register(PluginHost::IPlugin::INotification* sink) override {} - void Unregister(PluginHost::IPlugin::INotification* sink) override {} - void* QueryInterfaceByCallsign(const uint32_t id, const string& name) override { return nullptr; } - Core::hresult Activate(const reason why) override { return Core::ERROR_NONE; } - Core::hresult Deactivate(const reason why) override { return Core::ERROR_NONE; } - Core::hresult Unavailable(const reason why) override { return Core::ERROR_NONE; } - Core::hresult Hibernate(const uint32_t timeout) override { return Core::ERROR_NONE; } - uint32_t Submit(const uint32_t id, const Core::ProxyType& response) override { return Core::ERROR_NONE; } - - private: - string _config; - mutable uint32_t _refCount; - }; - -}; - -TEST_F(MessageControlL1Test, Construction) { - EXPECT_NE(nullptr, plugin.operator->()) << "Plugin instance should not be null"; -} - -TEST_F(MessageControlL1Test, InitialState) { - EXPECT_TRUE(plugin->Information().empty()) << "Initial plugin information should be empty"; -} - -TEST_F(MessageControlL1Test, EnableAllMessageTypes) { - std::vector types = { - Exchange::IMessageControl::TRACING, - Exchange::IMessageControl::LOGGING, - Exchange::IMessageControl::REPORTING, - Exchange::IMessageControl::STANDARD_OUT, - Exchange::IMessageControl::STANDARD_ERROR - }; - for (auto type : types) { - Core::hresult hr = plugin->Enable(type, "category1", "testmodule", true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable should succeed for type " << type; - } -} - -TEST_F(MessageControlL1Test, EnableTracing) { - Core::hresult hr = plugin->Enable( - Exchange::IMessageControl::TRACING, - "category1", - "testmodule", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable tracing should succeed"; -} - -TEST_F(MessageControlL1Test, EnableLogging) { - Core::hresult hr = plugin->Enable( - Exchange::IMessageControl::LOGGING, - "category1", - "testmodule", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable logging should succeed"; -} - -TEST_F(MessageControlL1Test, EnableDisableWarning) { - Core::hresult hr = plugin->Enable( - Exchange::IMessageControl::TRACING, - "category1", - "testmodule", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable tracing should succeed"; - hr = plugin->Enable( - Exchange::IMessageControl::TRACING, - "category1", - "testmodule", - false); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Disable tracing should succeed"; -} - -TEST_F(MessageControlL1Test, ControlsIterator) { - plugin->Enable(Exchange::IMessageControl::TRACING, "cat1", "mod1", true); - plugin->Enable(Exchange::IMessageControl::LOGGING, "cat2", "mod2", true); - Exchange::IMessageControl::IControlIterator* controls = nullptr; - Core::hresult hr = plugin->Controls(controls); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Controls should succeed"; - ASSERT_NE(nullptr, controls) << "Controls iterator should not be null"; - controls->Release(); -} - -TEST_F(MessageControlL1Test, WebSocketSupport) { - Core::ProxyType element = plugin->Inbound("test"); - EXPECT_TRUE(element.IsValid()) << "Inbound element should be valid"; -} - -TEST_F(MessageControlL1Test, EnableMultipleCategories) { - Core::hresult hr = plugin->Enable( - Exchange::IMessageControl::TRACING, - "category1", - "module1", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable tracing for category1 should succeed"; - hr = plugin->Enable( - Exchange::IMessageControl::TRACING, - "category2", - "module1", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable tracing for category2 should succeed"; -} - -TEST_F(MessageControlL1Test, EnableAndDisableMultiple) { - plugin->Enable(Exchange::IMessageControl::STANDARD_OUT, "cat1", "mod1", true); - plugin->Enable(Exchange::IMessageControl::STANDARD_ERROR, "cat2", "mod2", true); - plugin->Enable(Exchange::IMessageControl::STANDARD_OUT, "cat1", "mod1", false); - plugin->Enable(Exchange::IMessageControl::STANDARD_ERROR, "cat2", "mod2", false); - Exchange::IMessageControl::IControlIterator* controls = nullptr; - Core::hresult hr = plugin->Controls(controls); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Controls should succeed after enable/disable"; - controls->Release(); -} - -TEST_F(MessageControlL1Test, InboundCommunication) { - Core::ProxyType element = plugin->Inbound("command"); - EXPECT_TRUE(element.IsValid()) << "Inbound command should be valid"; - Core::ProxyType response = plugin->Inbound(1234, element); - EXPECT_TRUE(response.IsValid()) << "Inbound response should be valid"; -} - -TEST_F(MessageControlL1Test, WebSocketInboundFlow) { - Core::ProxyType element = plugin->Inbound("test"); - EXPECT_TRUE(element.IsValid()) << "Inbound test should be valid"; - Core::ProxyType response = plugin->Inbound(1234, element); - EXPECT_TRUE(response.IsValid()) << "Inbound response should be valid"; -} - -TEST_F(MessageControlL1Test, VerifyMultipleEnableDisable) { - for(auto type : { - Exchange::IMessageControl::TRACING, - Exchange::IMessageControl::LOGGING, - Exchange::IMessageControl::REPORTING}) { - Core::hresult hr = plugin->Enable(type, "category1", "testmodule", true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable should succeed for type " << type; - Exchange::IMessageControl::IControlIterator* controls = nullptr; - hr = plugin->Controls(controls); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Controls should succeed for type " << type; - ASSERT_NE(nullptr, controls) << "Controls iterator should not be null"; - controls->Release(); - hr = plugin->Enable(type, "category1", "testmodule", false); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Disable should succeed for type " << type; - } -} - -TEST_F(MessageControlL1Test, InboundMessageFlow) { - Core::ProxyType element = plugin->Inbound("command"); - EXPECT_TRUE(element.IsValid()) << "Inbound command should be valid"; - for(uint32_t id = 1; id < 4; id++) { - Core::ProxyType response = plugin->Inbound(id, element); - EXPECT_TRUE(response.IsValid()) << "Inbound response for id " << id << " should be valid"; - } -} - -TEST_F(MessageControlL1Test, AttachDetachChannel) { - _shell = new TestShell(); - _shellOwned = true; - ASSERT_NE(nullptr, _shell) << "Shell should not be null"; - string result = plugin->Initialize(_shell); - EXPECT_TRUE(result.empty()) << "Plugin should initialize with empty result"; - class TestChannel : public PluginHost::Channel { - public: - TestChannel() - : PluginHost::Channel(0, Core::NodeId("127.0.0.1", 8899)) - , _baseTime(static_cast(Core::Time::Now().Ticks())) { - State(static_cast(2), true); - } - void LinkBody(Core::ProxyType& request) override {} - void Received(Core::ProxyType& request) override {} - void Send(const Core::ProxyType& response) override {} - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override { return maxSendSize; } - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) override { return receivedSize; } - void StateChange() override {} - void Send(const Core::ProxyType& element) override {} - Core::ProxyType Element(const string& identifier) override { - return Core::ProxyType(); - } - void Received(Core::ProxyType& element) override {} - void Received(const string& text) override {} - private: - uint32_t _baseTime; - }; - TestChannel channel; - EXPECT_TRUE(plugin->Attach(channel)) << "Attach channel should succeed"; - plugin->Detach(channel); - plugin->Deinitialize(_shell); - delete _shell; - _shell = nullptr; - _shellOwned = false; -} - -TEST_F(MessageControlL1Test, MultipleAttachDetach) { - _shell = new TestShell(); - _shellOwned = true; - ASSERT_NE(nullptr, _shell) << "Shell should not be null"; - string result = plugin->Initialize(_shell); - EXPECT_TRUE(result.empty()) << "Plugin should initialize with empty result"; - class TestChannel : public PluginHost::Channel { - public: - TestChannel(uint32_t id) - : PluginHost::Channel(0, Core::NodeId("127.0.0.1", 8899)) - , _baseTime(static_cast(Core::Time::Now().Ticks())) - , _id(id) { - State(static_cast(2), true); - } - void LinkBody(Core::ProxyType& request) override {} - void Received(Core::ProxyType& request) override {} - void Send(const Core::ProxyType& response) override {} - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override { return maxSendSize; } - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) override { return receivedSize; } - void StateChange() override {} - void Send(const Core::ProxyType& element) override {} - Core::ProxyType Element(const string& identifier) override { - return Core::ProxyType(); - } - void Received(Core::ProxyType& element) override {} - void Received(const string& text) override {} - private: - uint32_t _baseTime; - uint32_t _id; - }; - TestChannel channel1(1); - TestChannel channel2(2); - TestChannel channel3(3); - EXPECT_TRUE(plugin->Attach(channel1)) << "Attach channel1 should succeed"; - EXPECT_TRUE(plugin->Attach(channel2)) << "Attach channel2 should succeed"; - EXPECT_TRUE(plugin->Attach(channel3)) << "Attach channel3 should succeed"; - plugin->Detach(channel2); - plugin->Detach(channel1); - plugin->Detach(channel3); - plugin->Deinitialize(_shell); - delete _shell; - _shell = nullptr; - _shellOwned = false; -} - -TEST_F(MessageControlL1Test, TextConvert_ForConsoleFormat) { - Publishers::Text textConv(Core::Messaging::MessageInfo::abbreviate::ABBREVIATED); - Core::Messaging::MessageInfo defaultMeta; - const string payload = "console-output-test"; - const string converted = textConv.Convert(defaultMeta, payload); - EXPECT_NE(string::npos, converted.find(payload)) << "Converted text should contain payload"; - EXPECT_NE(string::npos, converted.find("\n")) << "Converted text should contain newline"; -} - -TEST_F(MessageControlL1Test, SyslogOutput_ConverterOutput) { - Publishers::Text textConv(Core::Messaging::MessageInfo::abbreviate::ABBREVIATED); - Core::Messaging::MessageInfo defaultMeta; - const string payload = "syslog-output-test"; - const string converted = textConv.Convert(defaultMeta, payload); - EXPECT_NE(string::npos, converted.find(payload)) << "Converted text should contain payload"; -} - -TEST_F(MessageControlL1Test, WebSocketOutput_AttachCapacity_Command_Received) { - TestShell* shell = new TestShell(); - Publishers::WebSocketOutput ws; - ws.Initialize(shell, 1); - EXPECT_TRUE(ws.Attach(42)) << "Attach should succeed for id 42"; - EXPECT_FALSE(ws.Attach(43)) << "Attach should fail for id 43"; - Core::ProxyType cmd = ws.Command(); - EXPECT_TRUE(cmd.IsValid()) << "Command should be valid"; - Core::ProxyType ret = ws.Received(42, cmd); - EXPECT_TRUE(ret.IsValid()) << "Received should be valid for id 42"; - EXPECT_TRUE(ws.Detach(42)) << "Detach should succeed for id 42"; - ws.Deinitialize(); - delete shell; -} - -TEST_F(MessageControlL1Test, WebSocketOutput_Message_NoCrash_SubmitCalled) { - TestShell* shell = new TestShell(); - Publishers::WebSocketOutput ws; - ws.Initialize(shell, 2); - EXPECT_TRUE(ws.Attach(1001)) << "Attach should succeed for id 1001"; - Core::Messaging::MessageInfo defaultMeta; - ws.Message(defaultMeta, "websocket-export-test"); - EXPECT_TRUE(ws.Detach(1001)) << "Detach should succeed for id 1001"; - ws.Deinitialize(); - delete shell; -} - -TEST_F(MessageControlL1Test, MessageControl_InitializeCreatesFileOutput) { - TestShell* shell = new TestShell(R"({"filepath":"test_messagecontrol_init.log","abbreviated":true})"); - ASSERT_NE(nullptr, shell) << "Shell should not be null"; - string initResult = plugin->Initialize(shell); - EXPECT_TRUE(initResult.empty()) << "Plugin should initialize with empty result"; - const string expectedFile = "/tmp/test_messagecontrol_init.log"; - std::ifstream in(expectedFile); - if (in.good()) { - in.close(); - EXPECT_TRUE(std::ifstream(expectedFile).good()) << "File should exist after initialization"; - std::remove(expectedFile.c_str()); - } else { - GTEST_SKIP() << "Cannot create/read temp file in this environment; skipping file existence check."; - } - plugin->Deinitialize(shell); - delete shell; -} - -TEST_F(MessageControlL1Test, JSON_OutputOptions_TogglesAndConvert) { - Publishers::JSON json; - json.FileName(true); EXPECT_TRUE(json.FileName()) << "FileName option should be enabled"; - json.LineNumber(true); EXPECT_TRUE(json.LineNumber()) << "LineNumber option should be enabled"; - json.ClassName(true); EXPECT_TRUE(json.ClassName()) << "ClassName option should be enabled"; - json.Category(true); EXPECT_TRUE(json.Category()) << "Category option should be enabled"; - json.Module(true); EXPECT_TRUE(json.Module()) << "Module option should be enabled"; - json.Callsign(true); EXPECT_TRUE(json.Callsign()) << "Callsign option should be enabled"; - json.Date(true); EXPECT_TRUE(json.Date()) << "Date option should be enabled"; - json.Paused(false); EXPECT_FALSE(json.Paused()) << "Paused option should be disabled"; - json.FileName(false); EXPECT_FALSE(json.FileName()) << "FileName option should be disabled"; - json.Date(false); EXPECT_FALSE(json.Date()) << "Date option should be disabled"; - Core::Messaging::MessageInfo defaultMeta; - Publishers::JSON::Data data; - json.Convert(defaultMeta, "json-payload", data); - EXPECT_EQ(std::string("json-payload"), std::string(data.Message)) << "Converted message should match payload"; -} - -TEST_F(MessageControlL1Test, MessageOutput_SimpleText_JSON) { - Core::Messaging::MessageInfo defaultMeta; - Publishers::Text textConv(Core::Messaging::MessageInfo::abbreviate::ABBREVIATED); - const string payload = "hello-text"; - const string result = textConv.Convert(defaultMeta, payload); - EXPECT_NE(string::npos, result.find(payload)) << "Converted text should contain payload"; - Publishers::JSON::Data data; - Publishers::JSON jsonConv; - jsonConv.Convert(defaultMeta, "json-msg", data); - EXPECT_EQ(std::string("json-msg"), std::string(data.Message)) << "Converted message should match payload"; - Core::NodeId anyNode("127.0.0.1", 0); - Publishers::UDPOutput udp(anyNode); - udp.Message(defaultMeta, "udp-msg"); - SUCCEED() << "UDPOutput::Message should not crash"; -} - -TEST_F(MessageControlL1Test, MessageOutput_FileWrite) { - const string tmpName = "/tmp/test_messageoutput_filewrite.log"; - std::remove(tmpName.c_str()); - Publishers::FileOutput fileOutput(Core::Messaging::MessageInfo::abbreviate::ABBREVIATED, tmpName); - Core::Messaging::MessageInfo defaultMeta; - const string payload = "file-write-test-payload"; - fileOutput.Message(defaultMeta, payload); - std::ifstream in(tmpName); - if (in.good()) { - std::string content((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - in.close(); - EXPECT_NE(string::npos, content.find(payload)) << "File should contain payload"; - std::remove(tmpName.c_str()); - } else { - GTEST_SKIP() << "Cannot create/read temp file; skipping FileOutput write verification."; - } -} - -TEST_F(MessageControlL1Test, EnableWithEmptyFields) { - Core::hresult hr = plugin->Enable( - Exchange::IMessageControl::LOGGING, - "", - "", - true); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Enable with empty category/module should succeed"; -} - -TEST_F(MessageControlL1Test, WebSocketOutput_UnknownDetach) { - TestShell* shell = new TestShell(); - Publishers::WebSocketOutput ws; - ws.Initialize(shell, 1); - EXPECT_FALSE(ws.Detach(9999)) << "Detach should fail for unknown id"; - ws.Deinitialize(); - delete shell; -} - -TEST_F(MessageControlL1Test, TestShell_SubstituteAndMetadata) { - TestShell shell; - const string input = "replace-me"; - EXPECT_EQ(input, shell.Substitute(input)) << "Substitute should return input"; - string meta; - Core::hresult hr = shell.Metadata(meta); - EXPECT_EQ(Core::ERROR_NONE, hr) << "Metadata should succeed"; - EXPECT_TRUE(meta.size() >= 0) << "Metadata string should be non-negative length"; -} - -TEST_F(MessageControlL1Test, JSON_Paused_PreventsConvert) { - Publishers::JSON json; - Publishers::JSON::Data data; - json.Paused(true); - Core::Messaging::MessageInfo defaultMeta; - json.Convert(defaultMeta, "payload-should-be-ignored", data); - EXPECT_TRUE(std::string(data.Message).empty()) << "Message should be empty when paused"; -} - -TEST_F(MessageControlL1Test, Observer_Activated_Deactivated_Terminated_Simple) { - class MockConnection : public RPC::IRemoteConnection { - public: - MockConnection(uint32_t id) : _id(id) {} - uint32_t Id() const override { return _id; } - void AddRef() const override {} - uint32_t Release() const override { return 0; } - void* QueryInterface(const uint32_t) override { return nullptr; } - uint32_t RemoteId() const override { return _id; } - void* Acquire(uint32_t, const string&, uint32_t, uint32_t) override { return nullptr; } - void Terminate() override {} - uint32_t Launch() override { return 0; } - void PostMortem() override {} - private: - uint32_t _id; - }; - MockConnection connection(42); - _shell = new TestShell(); - _shellOwned = true; - plugin->Initialize(_shell); - plugin->Attach(connection.Id()); - SUCCEED() << "Activated should not crash"; - plugin->Detach(connection.Id()); - SUCCEED() << "Deactivated should not crash"; - plugin->Detach(connection.Id()); - SUCCEED() << "Terminated should not crash"; - plugin->Deinitialize(_shell); - delete _shell; - _shell = nullptr; - _shellOwned = false; -} - -TEST_F(MessageControlL1Test, ConsoleOutput_Message) { - Publishers::ConsoleOutput consoleOutput(Core::Messaging::MessageInfo::abbreviate::ABBREVIATED); - Core::Messaging::Metadata metadata(Core::Messaging::Metadata::type::TRACING, "TestCategory", "TestModule"); - ASSERT_TRUE(metadata.Type() == Core::Messaging::Metadata::type::TRACING) << "Metadata type should be TRACING"; - Core::Messaging::MessageInfo messageInfo(metadata, Core::Time::Now().Ticks()); - testing::internal::CaptureStdout(); - consoleOutput.Message(messageInfo, "Test message for ConsoleOutput"); - std::string output = testing::internal::GetCapturedStdout(); - EXPECT_NE(output.find("Test message for ConsoleOutput"), std::string::npos) << "Output should contain message"; - EXPECT_NE(output.find("TestCategory"), std::string::npos) << "Output should contain category"; - EXPECT_NE(output.find("TestModule"), std::string::npos) << "Output should contain module"; -} - -TEST_F(MessageControlL1Test, JSONOutput_ConvertWithOptions) { - Publishers::JSON json; - json.FileName(true); - json.LineNumber(true); - json.Category(true); - json.Module(true); - json.Callsign(true); - json.Date(true); - Core::Messaging::Metadata metadata(Core::Messaging::Metadata::type::TRACING, "JSONCategory", "JSONModule"); - Core::Messaging::MessageInfo messageInfo(metadata, Core::Time::Now().Ticks()); - Publishers::JSON::Data data; - json.Convert(messageInfo, "Test JSON message", data); - EXPECT_EQ(data.Category.Value(), "JSONCategory") << "Category should match"; - EXPECT_EQ(data.Module.Value(), "JSONModule") << "Module should match"; - EXPECT_EQ(data.Message.Value(), "Test JSON message") << "Message should match"; - EXPECT_FALSE(data.Time.Value().empty()) << "Time should not be empty"; -} diff --git a/Tests/L1Tests/tests/test_Migration.cpp b/Tests/L1Tests/tests/test_Migration.cpp deleted file mode 100644 index e011e2d..0000000 --- a/Tests/L1Tests/tests/test_Migration.cpp +++ /dev/null @@ -1,511 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "Migration.h" -#include "MigrationImplementation.h" -#include "ServiceMock.h" -#include "COMLinkMock.h" -#include "RfcApiMock.h" -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -using ::testing::NiceMock; -using namespace WPEFramework; - -class MigrationTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - Core::JSONRPC::Context connection; - Core::JSONRPC::Message message; - NiceMock service; - NiceMock comLinkMock; - Core::ProxyType MigrationImpl; - string response; - ServiceMock *p_serviceMock = nullptr; - RfcApiImplMock* p_rfcApiImplMock = nullptr ; - - MigrationTest() - : plugin(Core::ProxyType::Create()) - , handler(*plugin) - , connection(1,0,"") - { - p_serviceMock = new NiceMock ; - p_rfcApiImplMock = new NiceMock ; - RfcApi::setImpl(p_rfcApiImplMock); - - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const RPC::Object& object, const uint32_t waitTime, uint32_t& connectionId) { - MigrationImpl = Core::ProxyType::Create(); - return &MigrationImpl; - })); - - plugin->Initialize(&service); - } - - virtual ~MigrationTest() override - { - plugin->Deinitialize(&service); - - if (p_serviceMock != nullptr) - { - delete p_serviceMock; - p_serviceMock = nullptr; - } - - RfcApi::setImpl(nullptr); - if (p_rfcApiImplMock != nullptr) - { - delete p_rfcApiImplMock; - p_rfcApiImplMock = nullptr; - } - } - - // Helper methods for plugin lifecycle tests - Core::ProxyType CreateTestPlugin() - { - return Core::ProxyType::Create(); - } - - void SetupPluginInstantiateMock(uint32_t connectionId = 0) - { - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&, connectionId](const RPC::Object& object, const uint32_t waitTime, uint32_t& connId) { - MigrationImpl = Core::ProxyType::Create(); - if (connectionId != 0) { - connId = connectionId; - } - return &MigrationImpl; - })); - } - - void InitializeAndDeinitializePlugin(Core::ProxyType& testPlugin) - { - string result = testPlugin->Initialize(&service); - EXPECT_TRUE(result.empty()); - testPlugin->Deinitialize(&service); - } -}; - -TEST_F(MigrationTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getBootTypeInfo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setMigrationStatus"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getMigrationStatus"))); -} - -// Parameterized test for different boot types with expected values -class MigrationBootTypeTest : public MigrationTest, public ::testing::WithParamInterface> {}; -TEST_P(MigrationBootTypeTest, GetBootTypeInfo_Success) -{ - // Create the expected boot type file - const char* testFile = "/tmp/bootType"; - const char* bootTypeString = GetParam().first; - const char* expectedBootTypeString = GetParam().second; - - std::ofstream file(testFile); - file << "BOOT_TYPE=" << bootTypeString << "\n"; - file.close(); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getBootTypeInfo"), _T("{}"), response)); - - // Parse and validate the response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("bootType")) << "Response missing 'bootType' field. Response: " << response; - - // The API returns bootType as a string, validate it matches expected - std::string actualBootType = jsonResponse["bootType"].String(); - - EXPECT_EQ(actualBootType, std::string(expectedBootTypeString)) - << "Boot type mismatch for " << bootTypeString - << " - Expected: '" << expectedBootTypeString << "'" - << ", Got: '" << actualBootType << "'" - << ", Response: " << response; - - TEST_LOG("GetBootTypeInfo %s test PASSED - Expected and got boot type: '%s'", - bootTypeString, actualBootType.c_str()); - - // Clean up - std::remove(testFile); -} -INSTANTIATE_TEST_SUITE_P( - BootTypes, - MigrationBootTypeTest, - ::testing::Values( - std::make_pair("BOOT_INIT", "BOOT_INIT"), - std::make_pair("BOOT_NORMAL", "BOOT_NORMAL"), - std::make_pair("BOOT_MIGRATION", "BOOT_MIGRATION"), - std::make_pair("BOOT_UPDATE", "BOOT_UPDATE") - ) -); - -TEST_F(MigrationTest, GetBootTypeInfo_Failure_InvalidBootType) -{ - // Create the expected boot type file with invalid boot type - const char* testFile = "/tmp/bootType"; - std::ofstream file(testFile); - file << "BOOT_TYPE=INVALID_BOOT_TYPE\n"; - file.close(); - - EXPECT_EQ(1005, handler.Invoke(connection, _T("getBootTypeInfo"), _T("{}"), response)); - - // For error cases, the response body might be empty - just validate the error code was returned - // This is the expected behavior for JSONRPC APIs when they encounter errors - TEST_LOG("GetBootTypeInfo invalid boot type test PASSED - Error code 1005 returned as expected. Response: '%s'", response.c_str()); - - // Clean up - std::remove(testFile); -} - -TEST_F(MigrationTest, GetBootTypeInfo_Failure_FileReadError) -{ - // No file created, so readPropertyFromFile should fail - EXPECT_EQ(1005, handler.Invoke(connection, _T("getBootTypeInfo"), _T("{}"), response)); - - // For error cases, the response body might be empty - just validate the error code was returned - // This is the expected behavior for JSONRPC APIs when they encounter errors - TEST_LOG("GetBootTypeInfo file read error test PASSED - Error code 1005 returned as expected. Response: '%s'", response.c_str()); -} - -TEST_F(MigrationTest, SetMigrationStatus_Success_NOT_STARTED) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setMigrationStatus"), _T("{\"status\":\"NOT_STARTED\"}"), response)); - - // Validate success response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("success")) << "Response missing 'success' field. Response: " << response; - EXPECT_TRUE(jsonResponse["success"].Boolean()) << "SetMigrationStatus failed. Response: " << response; - - TEST_LOG("SetMigrationStatus NOT_STARTED test PASSED - Response: %s", response.c_str()); -} - -TEST_F(MigrationTest, SetMigrationStatus_Success_NOT_NEEDED) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setMigrationStatus"), _T("{\"status\":\"NOT_NEEDED\"}"), response)); - - // Validate success response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("success")) << "Response missing 'success' field. Response: " << response; - EXPECT_TRUE(jsonResponse["success"].Boolean()) << "SetMigrationStatus failed. Response: " << response; - - TEST_LOG("SetMigrationStatus NOT_NEEDED test PASSED - Response: %s", response.c_str()); -} - -TEST_F(MigrationTest, SetMigrationStatus_Success_STARTED) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setMigrationStatus"), _T("{\"status\":\"STARTED\"}"), response)); - - // Validate success response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("success")) << "Response missing 'success' field. Response: " << response; - EXPECT_TRUE(jsonResponse["success"].Boolean()) << "SetMigrationStatus failed. Response: " << response; - - TEST_LOG("SetMigrationStatus STARTED test PASSED - Response: %s", response.c_str()); -} - -TEST_F(MigrationTest, SetMigrationStatus_Success_PRIORITY_SETTINGS_MIGRATED) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setMigrationStatus"), _T("{\"status\":\"PRIORITY_SETTINGS_MIGRATED\"}"), response)); - - // Validate success response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("success")) << "Response missing 'success' field. Response: " << response; - EXPECT_TRUE(jsonResponse["success"].Boolean()) << "SetMigrationStatus failed. Response: " << response; - - TEST_LOG("SetMigrationStatus PRIORITY_SETTINGS_MIGRATED test PASSED - Response: %s", response.c_str()); -} - -// Parameterized test for SetMigrationStatus with different status values -class MigrationStatusTest : public MigrationTest, public ::testing::WithParamInterface {}; -TEST_P(MigrationStatusTest, SetMigrationStatus_Success) -{ - std::string request = std::string("{\"status\":\"") + GetParam() + "\"}"; - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setMigrationStatus"), Core::ToString(request), response)); - - // Validate success response - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON for " << GetParam() << ". Response: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("success")) << "Response missing 'success' field for " << GetParam() << ". Response: " << response; - EXPECT_TRUE(jsonResponse["success"].Boolean()) << "SetMigrationStatus failed for " << GetParam() << ". Response: " << response; - - TEST_LOG("SetMigrationStatus %s test PASSED - Response: %s", GetParam(), response.c_str()); -} -INSTANTIATE_TEST_SUITE_P( - SetMigrationStatusTests, - MigrationStatusTest, - ::testing::Values( - "DEVICE_SETTINGS_MIGRATED", - "CLOUD_SETTINGS_MIGRATED", - "APP_DATA_MIGRATED", - "MIGRATION_COMPLETED" - ) -); - -class GetMigrationStatusTest : public MigrationTest, public ::testing::WithParamInterface {}; -TEST_P(GetMigrationStatusTest, GetMigrationStatus_Success) -{ - const char* statusString = GetParam(); - - RFC_ParamData_t rfcParam; - strcpy(rfcParam.value, statusString); - - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::DoAll( - ::testing::SetArgPointee<2>(rfcParam), - ::testing::Return(WDMP_SUCCESS))); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getMigrationStatus"), _T("{}"), response)); - - // Validate response content - JsonObject jsonResponse; - ASSERT_TRUE(jsonResponse.FromString(response)) << "Failed to parse response JSON for " << statusString << ". Response: " << response; - ASSERT_TRUE(jsonResponse.HasLabel("migrationStatus")) << "Response missing 'migrationStatus' field for " << statusString << ". Response: " << response; - - // Get the migrationStatus value and handle both string and potential number cases - const Core::JSON::Variant& statusValue = jsonResponse["migrationStatus"]; - std::string actualStatus; - - // Try to get as string first - actualStatus = statusValue.String(); - - // If string is empty, it might be a number - if (actualStatus.empty()) { - int numericValue = statusValue.Number(); - TEST_LOG("DEBUG: migrationStatus appears to be numeric: %d, converting to string", numericValue); - - // Map numeric values to strings if needed - static const std::map statusMap = { - {0, "NOT_STARTED"}, - {1, "NOT_NEEDED"}, - {2, "STARTED"}, - {3, "PRIORITY_SETTINGS_MIGRATED"}, - {4, "DEVICE_SETTINGS_MIGRATED"}, - {5, "CLOUD_SETTINGS_MIGRATED"}, - {6, "APP_DATA_MIGRATED"}, - {7, "MIGRATION_COMPLETED"} - }; - - auto it = statusMap.find(numericValue); - if (it != statusMap.end()) { - actualStatus = it->second; - TEST_LOG("DEBUG: Mapped numeric value %d to string '%s'", numericValue, actualStatus.c_str()); - } else { - actualStatus = std::to_string(numericValue); - TEST_LOG("DEBUG: Unknown numeric value %d, using as string", numericValue); - } - } - - EXPECT_EQ(actualStatus, std::string(statusString)) - << "Migration status mismatch for " << statusString - << " - Expected: '" << statusString << "'" - << ", Got: '" << actualStatus << "'" - << ", Response: " << response; - - TEST_LOG("GetMigrationStatus %s test PASSED - Expected and got status: '%s'", - statusString, actualStatus.c_str()); -} -INSTANTIATE_TEST_SUITE_P( - GetMigrationStatusTests, - GetMigrationStatusTest, - ::testing::Values( - "NOT_STARTED", - "NOT_NEEDED", - "STARTED", - "PRIORITY_SETTINGS_MIGRATED", - "DEVICE_SETTINGS_MIGRATED", - "CLOUD_SETTINGS_MIGRATED", - "APP_DATA_MIGRATED", - "MIGRATION_COMPLETED" - ) -); - -// Test for invalid migration status - API behavior check -TEST_F(MigrationTest, SetMigrationStatus_InvalidStatus_APIBehavior) -{ - std::string request = "{\"status\":\"INVALID_STATUS\"}"; - uint32_t result = handler.Invoke(connection, _T("setMigrationStatus"), Core::ToString(request), response); - - // The API currently accepts invalid status strings and returns success - // This documents the current API behavior - it doesn't validate status strings strictly - EXPECT_EQ(result, Core::ERROR_NONE) << "API currently accepts invalid status values. Response: " << response; - - // Validate the response structure even for invalid inputs - JsonObject jsonResponse; - if (jsonResponse.FromString(response) && jsonResponse.HasLabel("success")) { - bool success = jsonResponse["success"].Boolean(); - EXPECT_TRUE(success); - TEST_LOG("SetMigrationStatus with invalid status returned success=%s (current API behavior)", - success ? "true" : "false"); - } - - TEST_LOG("SetMigrationStatus invalid status behavior test - API accepts invalid values, Response: %s", response.c_str()); -} - -// Test for missing parameters -TEST_F(MigrationTest, SetMigrationStatus_MissingParameter_APIBehavior) -{ - std::string request = "{}"; // Empty request - uint32_t result = handler.Invoke(connection, _T("setMigrationStatus"), Core::ToString(request), response); - - // Check if the API validates required parameters or has default behavior - if (result == Core::ERROR_NONE) { - TEST_LOG("SetMigrationStatus with empty request succeeded (API provides default behavior). Response: %s", response.c_str()); - - // Validate response structure - JsonObject jsonResponse; - if (jsonResponse.FromString(response) && jsonResponse.HasLabel("success")) { - bool success = jsonResponse["success"].Boolean(); - EXPECT_TRUE(success) << "Response should have valid success field. Response: " << response; - } - } else { - TEST_LOG("SetMigrationStatus with empty request failed as expected. Error code: %d, Response: %s", result, response.c_str()); - } -} - -// Test with malformed JSON - documenting actual API behavior -TEST_F(MigrationTest, SetMigrationStatus_MalformedJSON_APIBehavior) -{ - std::string request = "{ invalid json }"; // Malformed JSON - uint32_t result = handler.Invoke(connection, _T("setMigrationStatus"), Core::ToString(request), response); - - // The API surprisingly accepts even malformed JSON and returns success - // This documents the actual API behavior - very lenient input handling - EXPECT_EQ(result, Core::ERROR_NONE) << "API currently accepts malformed JSON (unexpected behavior). Response: " << response; - - // Validate the response structure - JsonObject jsonResponse; - if (jsonResponse.FromString(response)) { - if (jsonResponse.HasLabel("success")) { - bool success = jsonResponse["success"].Boolean(); - EXPECT_TRUE(success); - TEST_LOG("SetMigrationStatus with malformed JSON returned success=%s (very lenient API behavior)", - success ? "true" : "false"); - } - } - - TEST_LOG("SetMigrationStatus malformed JSON behavior test - API unexpectedly accepts malformed input, Response: %s", response.c_str()); -} - -// Test with completely invalid parameter structure - try to find actual error case -TEST_F(MigrationTest, SetMigrationStatus_InvalidParameterStructure) -{ - std::string request = "{\"wrongField\":123}"; // Completely wrong parameter structure - uint32_t result = handler.Invoke(connection, _T("setMigrationStatus"), Core::ToString(request), response); - - // Test if API validates parameter structure or just ignores unknown fields - if (result == Core::ERROR_NONE) { - TEST_LOG("SetMigrationStatus with wrong parameter structure succeeded (API ignores unknown fields). Response: %s", response.c_str()); - - // Validate response structure - JsonObject jsonResponse; - if (jsonResponse.FromString(response) && jsonResponse.HasLabel("success")) { - bool success = jsonResponse["success"].Boolean(); - EXPECT_TRUE(success) << "Response should have valid success field. Response: " << response; - } - } else { - TEST_LOG("SetMigrationStatus with wrong parameter structure failed. Error code: %d, Response: %s", result, response.c_str()); - } -} - - -// Test GetMigrationStatus failure when RFC fails -TEST_F(MigrationTest, GetMigrationStatus_Failure_RFCError) -{ - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(WDMP_FAILURE)); - - uint32_t result = handler.Invoke(connection, _T("getMigrationStatus"), _T("{}"), response); - - // Should return error when RFC fails - EXPECT_NE(result, Core::ERROR_NONE) << "GetMigrationStatus should fail when RFC fails. Response: " << response; - - TEST_LOG("GetMigrationStatus RFC failure test PASSED - Error code: %d, Response: %s", result, response.c_str()); -} - -//Plugin cases -TEST_F(MigrationTest, PluginInformation) -{ - string info = plugin->Information(); - EXPECT_TRUE(info.empty()); -} - -TEST_F(MigrationTest, PluginInitialize_Success) -{ - auto testPlugin = CreateTestPlugin(); - SetupPluginInstantiateMock(); - InitializeAndDeinitializePlugin(testPlugin); -} - -TEST_F(MigrationTest, PluginDeinitialize_WithValidMigration) -{ - auto testPlugin = CreateTestPlugin(); - SetupPluginInstantiateMock(); - - testPlugin->Initialize(&service); - testPlugin->Deinitialize(&service); -} - -TEST_F(MigrationTest, PluginDeinitialize_ConnectionTerminateException) -{ - auto testPlugin = CreateTestPlugin(); - NiceMock mockConnection; - SetupPluginInstantiateMock(1); // Set connection ID to 1 - - testPlugin->Initialize(&service); - testPlugin->Deinitialize(&service); -} - -TEST_F(MigrationTest, PluginDeactivated_MatchingConnectionId) -{ - auto testPlugin = CreateTestPlugin(); - NiceMock mockConnection; - SetupPluginInstantiateMock(123); // Set connection ID to 123 - - testPlugin->Initialize(&service); - - // Test Deactivated method by calling it directly - this tests the private method indirectly - // Since Deactivated is private, we can't call it directly, but we can test the scenario - // that would trigger it through connection handling - - testPlugin->Deinitialize(&service); -} - -TEST_F(MigrationTest, PluginDeactivated_NonMatchingConnectionId) -{ - auto testPlugin = CreateTestPlugin(); - NiceMock mockConnection; - SetupPluginInstantiateMock(123); // Set connection ID to 123 - - testPlugin->Initialize(&service); - testPlugin->Deinitialize(&service); -} diff --git a/Tests/L1Tests/tests/test_OCIContainer.cpp b/Tests/L1Tests/tests/test_OCIContainer.cpp deleted file mode 100755 index 1e5ae11..0000000 --- a/Tests/L1Tests/tests/test_OCIContainer.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include - -#include "OCIContainer.h" -#include "ServiceMock.h" -#include "DobbyMock.h" -#include "FactoriesImplementation.h" -#include "ThunderPortability.h" - -using namespace WPEFramework; -using ::testing::NiceMock; - -class OCIContainerTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - DECL_CORE_JSONRPC_CONX connection; - string response; - - OCIContainerTest() - : plugin(Core::ProxyType::Create()) - , handler(*(plugin)) - , INIT_CONX(1, 0) - { - } - virtual ~OCIContainerTest() = default; -}; - -class OCIContainerInitializedTest : public OCIContainerTest { -protected: - NiceMock service; - DobbyProxyMock *p_dobbymock = nullptr ; - IpcServiceMock *p_ipcservicemock = nullptr ; - - OCIContainerInitializedTest() - : OCIContainerTest() - { - p_dobbymock = new NiceMock ; - DobbyProxy::setImpl(p_dobbymock); - - p_ipcservicemock = new NiceMock ; - IpcService::setImpl(p_ipcservicemock); - - EXPECT_CALL(*p_ipcservicemock, start()) - .WillOnce(::testing::Return(true)); - - EXPECT_CALL(*p_dobbymock, registerListener(::testing::_, ::testing::_)) - .WillOnce(::testing::Return(5)); - - EXPECT_EQ(string(""), plugin->Initialize(&service)); - } - - virtual ~OCIContainerInitializedTest() override - { - EXPECT_CALL(*p_dobbymock, unregisterListener(5)) - .WillOnce(::testing::Return()); - - plugin->Deinitialize(&service); - DobbyProxy::setImpl(nullptr); - if (p_dobbymock != nullptr) - { - delete p_dobbymock; - p_dobbymock = nullptr; - } - IpcService::setImpl(nullptr); - if (p_ipcservicemock != nullptr) - { - delete p_ipcservicemock; - p_ipcservicemock = nullptr; - } - } -}; - - - -TEST_F(OCIContainerInitializedTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("listContainers"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getContainerState"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getContainerInfo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("startContainer"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("startContainerFromDobbySpec"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("stopContainer"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("pauseContainer"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("resumeContainer"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("executeCommand"))); -} - -TEST_F(OCIContainerInitializedTest, listContainersTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("listContainers"), _T("{}"), response)); - EXPECT_EQ(response, string("{\"containers\":[{\"Descriptor\":91,\"Id\":\"com.bskyb.epgui\"},{\"Descriptor\":94,\"Id\":\"Netflix\"}],\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, getContainerStateTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Running)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getContainerState"), _T("{" - "\"containerId\": \"com.bskyb.epgui\"}"), response)); - EXPECT_EQ(response, string("{\"state\":\"RUNNING\",\"success\":true,\"errorReason\":\"\"}")); -} - - -TEST_F(OCIContainerInitializedTest, getContainerInfoTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, getContainerInfo(91)) - .WillOnce(::testing::Return("{\"cpu\":{\"usage\" :{\"percpu\" :[3661526845,3773518079,4484546066,4700379608]," - "\"total\" : 16619970598}},\"gpu\":{\"memory\" :{\"failcnt\" : 0,\"limit\" : 209715200,\"max\" : 3911680,\"usage\" : 0}}," - "\"id\":\"Cobalt-0\",\"ion\":{\"heaps\" :{\"ion.\" :{\"failcnt\" : null,\"limit\" : null,\"max\" : null,\"usage\" : null}}}," - "\"memory\":{\"user\" :{\"failcnt\" : 0,\"limit\" : 419430400,\"max\" : 73375744,\"usage\" : 53297152}},\"pids\":[13132,13418]," - "\"processes\":[{\"cmdline\" : \"/usr/libexec/DobbyInit /usr/bin/WPEProcess -l libWPEFrameworkCobaltImpl.so -c" - " CobaltImplementation -C Cobalt-0 -r /tmp/communicator -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s" - " \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\" -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m" - " \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : \"/usr/libexec/DobbyInit\",\"nsPid\" : 1," - "\"pid\" : 13132},{\"cmdline\" : \"WPEProcess -l libWPEFrameworkCobaltImpl.so -c CobaltImplementation -C Cobalt-0 -r /tmp/communicator" - " -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\"" - " -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : " - "\"/usr/bin/WPEProcess\",\"nsPid\" : 6,\"pid\" : 13418}],\"state\":\"running\",\"timestamp\":1298657054196}")); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getContainerInfo"), _T("{" - "\"containerId\": \"com.bskyb.epgui\"}"), response)); - EXPECT_EQ(response, string("{\"info\":{\"cpu\":{\"usage\" :{\"percpu\" :[3661526845,3773518079,4484546066,4700379608]," - "\"total\" : 16619970598}},\"gpu\":{\"memory\" :{\"failcnt\" : 0,\"limit\" : 209715200,\"max\" : 3911680,\"usage\" : 0}}," - "\"id\":\"Cobalt-0\",\"ion\":{\"heaps\" :{\"ion.\" :{\"failcnt\" : null,\"limit\" : null,\"max\" : null,\"usage\" : null}}}," - "\"memory\":{\"user\" :{\"failcnt\" : 0,\"limit\" : 419430400,\"max\" : 73375744,\"usage\" : 53297152}},\"pids\":[13132,13418]," - "\"processes\":[{\"cmdline\" : \"/usr/libexec/DobbyInit /usr/bin/WPEProcess -l libWPEFrameworkCobaltImpl.so -c" - " CobaltImplementation -C Cobalt-0 -r /tmp/communicator -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s" - " \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\" -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m" - " \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : \"/usr/libexec/DobbyInit\",\"nsPid\" : 1," - "\"pid\" : 13132},{\"cmdline\" : \"WPEProcess -l libWPEFrameworkCobaltImpl.so -c CobaltImplementation -C Cobalt-0 -r /tmp/communicator" - " -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\"" - " -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : " - "\"/usr/bin/WPEProcess\",\"nsPid\" : 6,\"pid\" : 13418}],\"state\":\"running\",\"timestamp\":1298657054196},\"success\":true,\"errorReason\":\"\"}")); -} - - -TEST_F(OCIContainerInitializedTest, startContainerTest) -{ - EXPECT_CALL(*p_dobbymock, startContainerFromBundle(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("startContainer"), _T("{" - "\"containerId\": \"com.bskyb.epgui\", \"bundlePath\":\"/containers/myBundle\"," - "\"command\":\"command\", \"westerosSocket\":\"/usr/mySocket\", \"envvar\":[\"FOO=BAR\"]}"), response)); - EXPECT_EQ(response, string("{\"descriptor\":91,\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, startContainerFromDobbySpecTest) -{ - EXPECT_CALL(*p_dobbymock, startContainerFromSpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("startContainerFromDobbySpec"), _T("{" - "\"containerId\": \"com.bskyb.epgui\", \"dobbySpec\":\"/containers/dobbySpec\"," - "\"command\":\"command\", \"westerosSocket\":\"/usr/mySocket\"}"), response)); - EXPECT_EQ(response, string("{\"descriptor\":91,\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, stopContainerTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("stopContainer"), _T("{" - "\"containerId\": \"com.bskyb.epgui\", \"force\":true}"), response)); - EXPECT_EQ(response, string("{\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, pauseContainerTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, pauseContainer(91)) - .WillOnce(::testing::Return(true)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("pauseContainer"), _T("{" - "\"containerId\": \"com.bskyb.epgui\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, resumeContainerTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, resumeContainer(91)) - .WillOnce(::testing::Return(true)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("resumeContainer"), _T("{" - "\"containerId\": \"com.bskyb.epgui\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true,\"errorReason\":\"\"}")); -} - -TEST_F(OCIContainerInitializedTest, executeCommandTest) -{ - std::list> containerslist = {{91, "com.bskyb.epgui"},{94, "Netflix"}}; - EXPECT_CALL(*p_dobbymock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbymock, execInContainer(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("executeCommand"), _T("{" - "\"containerId\": \"com.bskyb.epgui\", \"options\":\"--cwd=PATH\", \"command\":\"/bin/sleep 5\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true,\"errorReason\":\"\"}")); -} diff --git a/Tests/L1Tests/tests/test_PackageManager.cpp b/Tests/L1Tests/tests/test_PackageManager.cpp deleted file mode 100644 index 854b8c6..0000000 --- a/Tests/L1Tests/tests/test_PackageManager.cpp +++ /dev/null @@ -1,1782 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PackageManager.h" -#include "PackageManagerImplementation.h" -#include "StorageManagerMock.h" -#include "ISubSystemMock.h" -#include "ServiceMock.h" -#include "COMLinkMock.h" -#include "ThunderPortability.h" -#include "WorkerPoolImplementation.h" -#include "FactoriesImplementation.h" - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define TIMEOUT (500) -#define TIMEOUT_FOR_PAUSE (200) -#define TIMEOUT_FOR_INIT (200) -#define TIMEOUT_FOR_INSTALL (200) - -using ::testing::NiceMock; -using namespace WPEFramework; -using namespace std; - -typedef enum : uint32_t { - PackageManager_invalidStatus = 0, - PackageManager_AppDownloadStatus, - PackageManager_AppInstallStatus -} PackageManagerTest_status_t; - -struct StatusParams { - string packageId; - string version; - string downloadId; - string fileLocator; - Exchange::IPackageDownloader::Reason reason; -}; - -class PackageManagerTest : public ::testing::Test { -protected: - // Declare the protected members - ServiceMock* mServiceMock = nullptr; - StorageManagerMock* mStorageManagerMock = nullptr; - SubSystemMock* mSubSystemMock = nullptr; - - Core::ProxyType plugin; - Core::JSONRPC::Handler& mJsonRpcHandler; - Core::JSONRPC::Message message; - DECL_CORE_JSONRPC_CONX connection; - string mJsonRpcResponse; - string uri; - - PLUGINHOST_DISPATCHER *dispatcher; - FactoriesImplementation factoriesImplementation; - - Core::ProxyType mPackageManagerImpl; - Core::ProxyType workerPool; - - Exchange::IPackageDownloader* pkgdownloaderInterface = nullptr; - Exchange::IPackageInstaller* pkginstallerInterface = nullptr; - Exchange::IPackageHandler* pkghandlerInterface = nullptr; - Exchange::IPackageDownloader::Options options; - Exchange::IPackageDownloader::DownloadId downloadId; - Exchange::IPackageDownloader::ProgressInfo progress; - Exchange::IPackageDownloader::PackageInfo packageInfo; - std::list packageInfoList; - Exchange::IPackageDownloader::IPackageInfoIterator* packageInfoIterator = nullptr; - - // Constructor - PackageManagerTest() - : workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)), - plugin(Core::ProxyType::Create()), - mJsonRpcHandler(*plugin), - INIT_CONX(1,0) - { - mPackageManagerImpl = Core::ProxyType::Create(); - - pkgdownloaderInterface = static_cast(mPackageManagerImpl->QueryInterface(Exchange::IPackageDownloader::ID)); - - pkginstallerInterface = static_cast(mPackageManagerImpl->QueryInterface(Exchange::IPackageInstaller::ID)); - - pkghandlerInterface = static_cast(mPackageManagerImpl->QueryInterface(Exchange::IPackageHandler::ID)); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - - // Destructor - virtual ~PackageManagerTest() override - { - pkgdownloaderInterface->Release(); - pkginstallerInterface->Release(); - pkghandlerInterface->Release(); - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - } - - void SetUp() override - { - // Set up mocks and expect calls - mServiceMock = new NiceMock; - mStorageManagerMock = new NiceMock; - mSubSystemMock = new NiceMock; - - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t, const std::string& name) -> void* { - if (name == "org.rdk.StorageManager") { - return reinterpret_cast(mStorageManagerMock); - } - return nullptr; - })); - - EXPECT_CALL(*mServiceMock, ConfigLine()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return("{\"downloadDir\": \"/opt/CDL/\"}")); - - EXPECT_CALL(*mServiceMock, SubSystems()) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Return(mSubSystemMock)); - } - - void initforJsonRpc() - { - EXPECT_CALL(*mServiceMock, Register(::testing::_)) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mServiceMock, AddRef()) - .Times(::testing::AnyNumber()); - - // Activate the dispatcher and initialize the plugin for JSON-RPC - PluginHost::IFactories::Assign(&factoriesImplementation); - dispatcher = static_cast(plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); - dispatcher->Activate(mServiceMock); - plugin->Initialize(mServiceMock); - } - - void initforComRpc() - { - EXPECT_CALL(*mServiceMock, AddRef()) - .Times(::testing::AnyNumber()); - - // Initialize the plugin for COM-RPC - pkgdownloaderInterface->Initialize(mServiceMock); - } - - void getDownloadParams() - { - // Initialize the parameters required for COM-RPC with default values - uri = "https://www.examplefile.com/file-download/328"; - - options = { - true,2,1024 - }; - - downloadId = {}; - } - - void TearDown() override - { - // Clean up mocks - if (mServiceMock != nullptr) - { - delete mServiceMock; - mServiceMock = nullptr; - } - - if(mSubSystemMock != nullptr) - { - delete mSubSystemMock; - mSubSystemMock = nullptr; - } - } - - void deinitforJsonRpc() - { - EXPECT_CALL(*mServiceMock, Unregister(::testing::_)) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mServiceMock, Release()) - .Times(::testing::AnyNumber()); - - // Deactivate the dispatcher and deinitialize the plugin for JSON-RPC - dispatcher->Deactivate(); - dispatcher->Release(); - - plugin->Deinitialize(mServiceMock); - - if(mStorageManagerMock != nullptr) - { - delete mStorageManagerMock; - mStorageManagerMock = nullptr; - } - } - - void deinitforComRpc() - { - EXPECT_CALL(*mServiceMock, Release()) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mStorageManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mStorageManagerMock; - mStorageManagerMock = nullptr; - return 0; - })); - - // Deinitialize the plugin for COM-RPC - pkgdownloaderInterface->Deinitialize(mServiceMock); - } - - void waitforSignal(uint32_t timeout_ms) - { - std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms)); - } -}; - -class NotificationTest : public Exchange::IPackageDownloader::INotification, - public Exchange::IPackageInstaller::INotification -{ - private: - BEGIN_INTERFACE_MAP(NotificationTest) - INTERFACE_ENTRY(Exchange::IPackageDownloader::INotification) - INTERFACE_ENTRY(Exchange::IPackageInstaller::INotification) - END_INTERFACE_MAP - - public: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Status signal flag */ - uint32_t m_status_signal = PackageManager_invalidStatus; - - StatusParams m_status_param; - - NotificationTest(){} - ~NotificationTest(){} - - void SetStatusParams(const StatusParams& statusParam) - { - m_status_param = statusParam; - } - - void OnAppDownloadStatus(Exchange::IPackageDownloader::IPackageInfoIterator* const packageInfos) override - { - m_status_signal = PackageManager_AppDownloadStatus; - JsonValue downloadId; - JsonValue fileLocator; - JsonValue failReason; - - std::unique_lock lock(m_mutex); - if(packageInfos != nullptr) - { - Exchange::IPackageDownloader::PackageInfo resultItem{}; - - while (packageInfos->Next(resultItem) == true) - { - downloadId = resultItem.downloadId; - fileLocator = resultItem.fileLocator; - failReason = (resultItem.reason == Exchange::IPackageDownloader::Reason::NONE) ? "NONE" : - (resultItem.reason == Exchange::IPackageDownloader::Reason::DOWNLOAD_FAILURE) ? "DOWNLOAD_FAILURE" : - (resultItem.reason == Exchange::IPackageDownloader::Reason::DISK_PERSISTENCE_FAILURE) ? "DISK_PERSISTENCE_FAILURE" : "UNKNOWN"; - } - } - - EXPECT_EQ(m_status_param.downloadId, downloadId.String()); - - m_condition_variable.notify_one(); - } - - void OnAppInstallationStatus(const string& jsonresponse) override - { - m_status_signal = PackageManager_AppInstallStatus; - JsonValue packageId; - JsonValue version; - - JsonArray arr; - if(arr.IElement::FromString(jsonresponse) && arr.Length() > 0) { - JsonObject obj = arr[0].Object(); - packageId = obj["packageId"]; - version = obj["version"]; - } - - std::unique_lock lock(m_mutex); - EXPECT_EQ(m_status_param.packageId, packageId.String()); - EXPECT_EQ(m_status_param.version, version.String()); - - m_condition_variable.notify_one(); - } - - uint32_t WaitForStatusSignal(uint32_t timeout_ms, PackageManagerTest_status_t status) - { - uint32_t status_signal = PackageManager_invalidStatus; - std::unique_lock lock(m_mutex); - auto now = std::chrono::steady_clock::now(); - auto timeout = std::chrono::milliseconds(timeout_ms); - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - return m_status_signal; - } - status_signal = m_status_signal; - m_status_signal = PackageManager_invalidStatus; - return status_signal; - } - }; - -/* Test Case for verifying registered methods using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Check if the methods listed exist by using the Exists() from the JSON RPC handler - * Verify the methods exist by asserting that Exists() returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, registeredMethodsusingJsonRpc) { - - initforJsonRpc(); - - // TC-1: Check if the listed methods exist using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("download"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("pause"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("resume"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("cancel"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("delete"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("progress"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getStorageInformation"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("rateLimit"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("install"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("uninstall"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("listPackages"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("config"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("packageState"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("lock"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("unlock"))); - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Exists(_T("getLockedInfo"))); - - deinitforJsonRpc(); -} - -/* Test Case for adding download request to a regular queue using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, notifications/events, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, downloadMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - Core::Event onAppDownloadStatus(false, true); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - onAppDownloadStatus.SetEvent(); - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onAppDownloadStatus"), _T("org.rdk.PackageManagerRDKEMS"), message); - - // TC-2: Add download request to regular queue using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - EXPECT_EQ(Core::ERROR_NONE, onAppDownloadStatus.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppDownloadStatus"), _T("org.rdk.PackageManagerRDKEMS"), message); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - deinitforJsonRpc(); -} - -/* Test Case for checking download request error when internet is unavailable using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the method using the JSON RPC handler, passing the required parameters - * Verify download method error due to unavailability of internet by asserting that it returns Core::ERROR_UNAVAILABLE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, downloadMethodusingJsonRpcError) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return false; - })); - - // TC-3: Download request error when internet is unavailable using JsonRpc - EXPECT_EQ(Core::ERROR_UNAVAILABLE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for adding download request to a priority queue using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters, setting priority as true and wait - * Verify successful download request by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, downloadMethodsusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uri = "https://httpbin.org/bytes/1024"; - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type){ - return true; - })); - - // TC-4: Add download request to priority queue using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - deinitforComRpc(); -} - -/* Test Case for checking download request error when internet is unavailable using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters - * Verify download method error due to unavailability of internet by asserting that it returns Core::ERROR_UNAVAILABLE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, downloadMethodsusingComRpcError) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type){ - return false; - })); - - // TC-5: Download request error when internet is unavailable using ComRpc - EXPECT_EQ(Core::ERROR_UNAVAILABLE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - deinitforComRpc(); -} - -/* Test Case for pausing download via ID using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters and wait - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the pause method using the JSON RPC handler, passing the downloadId - * Verify that the pause method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the cancel method using the JSON RPC handler, passing the downloadId for cancelling download - * Verify that the cancel method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, pauseMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://www.examplefile.com/file-download/328\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - // TC-6: Pause download via downloadId using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for pausing failed using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the pause method using the JSON RPC handler, passing downloadId - * Verify pause method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, pauseMethodusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-7: Failure in pausing download using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for pausing download via ID using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notificatios/events, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the pause method using the COM RPC interface, passing the downloadId - * Verify successful pause by asserting that it returns Core::ERROR_NONE - * Call the cancel method using the COM RPC interface, passing the downloadId for cancelling download - * Verify successful cancel by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, pauseMethodusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string downloadIdStr = "1001"; - - // TC-8: Pause download via downloadId using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Pause(downloadIdStr)); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Cancel(downloadIdStr)); - - deinitforComRpc(); -} - -/* Test Case for pausing failed using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the pause method using the COM RPC interface, passing downloadId - * Verify pause method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, pauseMethodusingComRpcFailure) { - - initforComRpc(); - - string downloadId = "1001"; - - // TC-9: Failure in pausing download using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->Pause(downloadId)); - - deinitforComRpc(); -} - -/* Test Case for resuming download via ID using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters and wait - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the pause method using the JSON RPC handler, passing the downloadId - * Verify that the pause method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the resume method using the JSON RPC handler, passing the downloadId - * Verify that the resume method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the cancel method using the JSON RPC handler, passing the downloadId for cancelling download - * Verify that the cancel method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, resumeMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://www.examplefile.com/file-download/328\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - // TC-10: Resume download via downloadId using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("resume"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - - /* Test Case for resuming failed using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the resume method using the JSON RPC handler, passing downloadId - * Verify resume method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, resumeMethodusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-11: Failure in resuming download using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("resume"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - - /* Test Case for resuming download via ID using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the pause method using the COM RPC interface, passing the downloadId - * Verify successful pause by asserting that it returns Core::ERROR_NONE - * Call the resume method using the COM RPC interface, passing the downloadId - * Verify successful resume by asserting that it returns Core::ERROR_NONE - * Call the cancel method using the COM RPC interface, passing the downloadId for cancelling download - * Verify successful cancel by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, resumeMethodusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string downloadIdStr = "1001"; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Pause(downloadIdStr)); - - // TC-12: Resume download via downloadId using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Resume(downloadIdStr)); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Cancel(downloadIdStr)); - - deinitforComRpc(); -} - - /* Test Case for resuming failed using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the resume method using the COM RPC interface, passing downloadId - * Verify resume method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, resumeMethodusingComRpcFailure) { - - initforComRpc(); - - string downloadId = "1001"; - - // TC-13: Failure in resuming download using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->Resume(downloadId)); - - deinitforComRpc(); -} - -/* Test Case for cancelling download via ID using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters and wait - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the pause method using the JSON RPC handler, passing the downloadId - * Verify that the pause method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the cancel method using the JSON RPC handler, passing the downloadId - * Verify that the cancel method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, cancelMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://www.examplefile.com/file-download/328\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - // TC-14: Cancel download via downloadId using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for cancelling failed using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the cancel method using the JSON RPC handler, passing downloadId - * Verify cancel method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, cancelMethodusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-15: Failure in cancelling download using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for cancelling download via ID using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the pause method using the COM RPC interface, passing the downloadId - * Verify successful pause by asserting that it returns Core::ERROR_NONE - * Call the cancel method using the COM RPC interface, passing the downloadId - * Verify successful cancel by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, cancelMethodusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string downloadIdStr = "1001"; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Pause(downloadIdStr)); - - // TC-16: Cancel download via downloadId using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Cancel(downloadIdStr)); - - deinitforComRpc(); -} - -/* Test Case for cancelling failed using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the cancel method using the COM RPC interface, passing downloadId - * Verify cancel method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, cancelMethodusingComRpcFailure) { - - initforComRpc(); - - string downloadId = "1001"; - - // TC-17: Failure in cancelling download using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->Cancel(downloadId)); - - deinitforComRpc(); -} - -/* Test Case for delete download using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, notifications/events, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the delete method using the JSON RPC handler, passing the fileLocator - * Verify successful delete by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, deleteMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - Core::Event onAppDownloadStatus(false, true); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mServiceMock, Submit(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - onAppDownloadStatus.SetEvent(); - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onAppDownloadStatus"), _T("org.rdk.PackageManagerRDKEMS"), message); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - EXPECT_EQ(Core::ERROR_NONE, onAppDownloadStatus.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onAppDownloadStatus"), _T("org.rdk.PackageManagerRDKEMS"), message); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - // TC-18: Delete download using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("delete"), _T("{\"fileLocator\": \"/opt/CDL/package1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for delete failed using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the delete method using the JSON RPC handler, passing fileLocator - * Verify delete method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, deleteMethodusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-19: Failure in delete using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("delete"), _T("{\"fileLocator\": \"\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for delete download using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the delete method using the COM RPC interface, passing fileLocator - * Verify successful delete by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, deleteMethodusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uint32_t timeout_ms = 4000; - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(timeout_ms); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string fileLocator = "/opt/CDL/package1001"; - - // TC-20: Delete download failure when download in progress using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Delete(fileLocator)); - - deinitforComRpc(); -} - -/* Test Case for delete download failure using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the delete method using the COM RPC interface, passing fileLocator as empty string - * Verify delete method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, deleteMethodusingComRpcFailure) { - - initforComRpc(); - - string fileLocator = ""; - - // TC-21: Failure in delete using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->Delete(fileLocator)); - - deinitforComRpc(); -} - -/* Test Case for download progress via ID using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters and wait - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the pause method using the JSON RPC handler, passing the downloadId - * Verify that the pause method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the progress method using the JSON RPC handler, passing the downloadId and progress info - * Verify that the progress method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking that response is not empty string. - * Invoke the cancel method using the JSON RPC handler, passing the downloadId for cancelling download - * Verify that the cancel method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, progressMethodusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://www.examplefile.com/file-download/328\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - // TC-22: Download progress via downloadId using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("progress"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - EXPECT_NE(mJsonRpcResponse, ""); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for download progress failure using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the progress method using the JSON RPC handler, passing downloadId and progress info - * Verify progress method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, progressMethodusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-23: Download progress failure using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("progress"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for download progress via ID using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the pause method using the COM RPC interface along with downloadId - * Verify successful pause by asserting that it returns Core::ERROR_NONE - * Call the progress method using the COM RPC interface, passing the downloadId and progress info - * Verify successful progress by asserting that it returns Core::ERROR_NONE and checking that progress is non-zero - * Call the cancel method using the COM RPC interface, passing the downloadId for cancelling download - * Verify successful cancel by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, progressMethodusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - progress = {}; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string downloadIdStr = "1001"; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Pause(downloadIdStr)); - - // TC-24: Download progress via downloadId using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Progress(downloadIdStr, progress)); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Cancel(downloadIdStr)); - - deinitforComRpc(); -} - -/* Test Case for download progress failure using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the progress method using the COM RPC interface, passing downloadId and progress info - * Verify progress method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, progressMethodusingComRpcFailure) { - - initforComRpc(); - - progress = {}; - - string downloadId = "1001"; - - // TC-25: Progress failure via downloadId using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->Progress(downloadId, progress)); - - deinitforComRpc(); -} - -/* Test Case for getting storage information using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the getStorageInformation method using the JSON RPC handler, passing required parameters - * Verify getStorageInformation method success by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, getStorageInformationusingJsonRpc) { - - initforJsonRpc(); - - // TC-26: Get Storage Details using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("getStorageInformation"), _T("{\"quotaKB\": 1024, \"usedKB\": 568}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for getting storage information using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the getStorageInformation method using the COM RPC interface, passing required parameters - * Verify getStorageInformation method success by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, getStorageInformationusingComRpc) { - - initforComRpc(); - - uint32_t quotaKB = 1024; - uint32_t usedKB = 568; - - // TC-27: Get Storage Details using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->GetStorageInformation(quotaKB, usedKB)); - - deinitforComRpc(); -} - -/* Test Case for setting rate limit via ID using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters and wait - * Verify that the download method is invoked successfully by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Invoke the pause method using the JSON RPC handler, passing the downloadId - * Verify that the pause method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the rateLimit method using the JSON RPC handler, passing the downloadId and the limit - * Verify that the rateLimit method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Invoke the cancel method using the JSON RPC handler, passing the downloadId for cancelling download - * Verify that the cancel method is invoked successfully by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, rateLimitusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://www.examplefile.com/file-download/328\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_NE(mJsonRpcResponse.find("1001"), std::string::npos); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("pause"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - // TC-28: Set rate limit via downloadID using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("rateLimit"), _T("{\"downloadId\": \"1001\", \"limit\": 1024}"), mJsonRpcResponse)); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("cancel"), _T("{\"downloadId\": \"1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - - /* Test Case for setting rate limit failure using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the rateLimit method using the JSON RPC handler, passing downloadId and limit - * Verify rateLimit method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, rateLimitusingJsonRpcFailure) { - - initforJsonRpc(); - - // TC-29: Rate limit failure using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("rateLimit"), _T("{\"downloadId\": \"1001\", \"limit\": 1024}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for setting rate limit via ID using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Obtain the required parameters for downloading using the getDownloadParams() - * Call the Download method using the COM RPC interface along with the required parameters and wait - * Verify successful download by asserting that it returns Core::ERROR_NONE and checking the downloadId - * Call the Pause method using the COM RPC interface along with downloadId - * Verify successful pause by asserting that it returns Core::ERROR_NONE - * Call the rateLimit method using the COM RPC interface, passing the downloadId and limit - * Verify rateLimit is set successfully by asserting that it returns Core::ERROR_NONE - * Call the cancel method using the COM RPC interface, passing the downloadId for cancelling download - * Verify successful cancel by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, rateLimitusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - uint64_t limit = 1024; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - waitforSignal(TIMEOUT_FOR_PAUSE); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - string downloadIdStr = "1001"; - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Pause(downloadIdStr)); - - // TC-30: Set rate limit via downloadID using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->RateLimit(downloadIdStr, limit)); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Cancel(downloadIdStr)); - - deinitforComRpc(); -} - -/* Test Case for failure in setting rateLimit using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the rateLimit method using the COM RPC interface, passing downloadId and limit - * Verify rateLimit method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, rateLimitusingComRpcFailure) { - - initforComRpc(); - - uint64_t limit = 1024; - string downloadId = "1001"; - - // TC-31: Rate limit failure using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkgdownloaderInterface->RateLimit(downloadId, limit)); - - deinitforComRpc(); -} - -// IPackageInstaller methods - -/* Test Case for error on install due to invalid signature using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the install method using the JSON RPC handler, passing the required parameters, keeping the file locator field empty - * Verify that the install method fails by asserting that it returns Core::ERROR_INVALID_SIGNATURE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, installusingJsonRpcInvalidSignature) { - - initforJsonRpc(); - - waitforSignal(TIMEOUT_FOR_INIT); - - // TC-32: Error on install due to invalid signature using JsonRpc - EXPECT_EQ(Core::ERROR_INVALID_SIGNATURE, mJsonRpcHandler.Invoke(connection, _T("install"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\", \"additionalMetadata\": [{\"name\": \"testApp\", \"value\": \"2\"}], \"fileLocator\": \"\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for install success using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters, verify successful download and wait - * Invoke the install method using the JSON RPC handler, passing the required parameters - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, installusingJsonRpcSuccess) { - - initforJsonRpc(); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT); - - // TC-33: Install using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("install"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\", \"additionalMetadata\": [{\"name\": \"testApp\", \"value\": \"2\"}], \"fileLocator\": \"/opt/CDL/package1001\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - - /* Test Case for error on install due to invalid signature using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the install method using the COM RPC interface, passing required parameters, keeping the fileLocator parameter as empty and wait - * Verify error on install by asserting that it returns Core::ERROR_INVALID_SIGNATURE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, installusingComRpcInvalidSignature) { - - initforComRpc(); - - string packageId = "YouTube"; - string version = "100.1.24"; - string fileLocator = ""; - Exchange::IPackageInstaller::FailReason reason = Exchange::IPackageInstaller::FailReason::NONE; - list kv = { {"testapp", "2"} }; - - auto additionalMetadata = Core::Service>::Create(kv); - - waitforSignal(TIMEOUT_FOR_INIT); - - // TC-34: Error on install due to invalid signature using ComRpc - EXPECT_EQ(Core::ERROR_INVALID_SIGNATURE, pkginstallerInterface->Install(packageId, version, additionalMetadata, fileLocator, reason)); - - deinitforComRpc(); -} - -/* Test Case for install success using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Call the download method using the COM-RPC interface, passing required parameters for download, verify and wait - * Call the install method using the COM RPC interface, passing required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - - TEST_F(PackageManagerTest, installusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uri = "https://httpbin.org/bytes/1024"; - - uint32_t timeout_ms = 3000; - - string packageId = "YouTube"; - string version = "100.1.24"; - string fileLocator = "/opt/CDL/package1001"; - Exchange::IPackageInstaller::FailReason reason = Exchange::IPackageInstaller::FailReason::NONE; - list kv = { {"testapp", "2"} }; - - auto additionalMetadata = Core::Service>::Create(kv); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mStorageManagerMock, CreateStorage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const uint32_t &size, string& path, string &errorReason) { - return Core::ERROR_NONE; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - waitforSignal(TIMEOUT); - - // TC-35: Install using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->Install(packageId, version, additionalMetadata, fileLocator, reason)); - - waitforSignal(timeout_ms); - - deinitforComRpc(); -} - -/* Test Case for uninstall success using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters, verify successful download and wait - * Invoke the install method using the JSON RPC handler, passing the required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Invoke the uninstall method using the JSON RPC handler, passing the required parameters - * Verify successful uninstall by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, uninstallusingJsonRpcSuccess) { - - initforJsonRpc(); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("install"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\", \"additionalMetadata\": [{\"name\": \"testApp\", \"value\": \"2\"}], \"fileLocator\": \"/opt/CDL/package1001\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_INSTALL); - - // TC-36: Uninstall using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("uninstall"), _T("{\"packageId\": \"YouTube\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for uninstall success using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Call the download method using the COM-RPC interface, passing required parameters for download, verify and wait - * Call the install method using the COM RPC interface, passing required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Call the uninstall method using the COM RPC interface, passing required parameters and wait - * Verify successful uninstall by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, uninstallusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uri = "https://httpbin.org/bytes/1024"; - - uint32_t timeout_ms = 3000; - - string packageId = "YouTube"; - string errorReason = "no error"; - string version = "100.1.24"; - string fileLocator = "/opt/CDL/package1001"; - Exchange::IPackageInstaller::FailReason reason = Exchange::IPackageInstaller::FailReason::NONE; - list kv = { {"testapp", "2"} }; - - auto additionalMetadata = Core::Service>::Create(kv); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mStorageManagerMock, CreateStorage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const uint32_t &size, string& path, string &errorReason) { - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*mStorageManagerMock, DeleteStorage(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, string &errorReason) { - return Core::ERROR_NONE; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->Install(packageId, version, additionalMetadata, fileLocator, reason)); - - waitforSignal(timeout_ms); - - // TC-37: Uninstall using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->Uninstall(packageId, errorReason)); - - waitforSignal(timeout_ms); - - deinitforComRpc(); -} - -/* Test Case for list packages method success using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters, verify successful download and wait - * Invoke the install method using the JSON RPC handler, passing the required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Invoke the listPackages method using the JSON RPC handler, passing the required parameters - * Verify that the listPackages method is successful by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, listPackagesusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("install"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\", \"additionalMetadata\": [{\"name\": \"testApp\", \"value\": \"2\"}], \"fileLocator\": \"/opt/CDL/package1001\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_INSTALL); - - // TC-38: list packages using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("listPackages"), _T("{\"packages\": {}}"), mJsonRpcResponse)); - - EXPECT_NE(mJsonRpcResponse, ""); - - deinitforJsonRpc(); -} - -/* Test Case for list packages method success using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the download method using the COM-RPC interface, passing required parameters for download, verify and wait - * Call the install method using the COM RPC interface, passing required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Call the ListPackages method using the COM RPC interface, passing the required parameters - * Verify that the ListPackages method is successful by asserting that it returns Core::ERROR_NONE - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, listPackagesusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uri = "https://httpbin.org/bytes/1024"; - - string packageId = "YouTube"; - string version = "100.1.24"; - string fileLocator = "/opt/CDL/package1001"; - Exchange::IPackageInstaller::FailReason reason = Exchange::IPackageInstaller::FailReason::NONE; - list kv = { {"testapp", "2"} }; - - list packageList = { {} }; - - auto packages = Core::Service>::Create(packageList); - - auto additionalMetadata = Core::Service>::Create(kv); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mStorageManagerMock, CreateStorage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const uint32_t &size, string& path, string &errorReason) { - return Core::ERROR_NONE; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->Install(packageId, version, additionalMetadata, fileLocator, reason)); - - waitforSignal(TIMEOUT_FOR_INSTALL); - - // TC-39: list packages using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->ListPackages(packages)); - - deinitforComRpc(); -} - -/* Test Case for package state failure using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the download method using the JSON RPC handler, passing the required parameters, verify successful download and wait - * Invoke the install method using the JSON RPC handler, passing the required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Invoke the packageState method using the JSON RPC handler, passing the required parameters - * Verify packageState method success by asserting that it returns Core::ERROR_NONE - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, packageStateusingJsonRpcSuccess) { - - initforJsonRpc(); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("download"), _T("{\"url\": \"https://httpbin.org/bytes/1024\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("install"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\", \"additionalMetadata\": [{\"name\": \"testApp\", \"value\": \"2\"}], \"fileLocator\": \"/opt/CDL/package1001\"}"), mJsonRpcResponse)); - - waitforSignal(TIMEOUT_FOR_INSTALL); - - // TC-40: Package state using JsonRpc - EXPECT_EQ(Core::ERROR_NONE, mJsonRpcHandler.Invoke(connection, _T("packageState"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for package state failure using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, notifications/events, mocks and expectations - * Call the download method using the COM-RPC interface, passing required parameters for download, verify and wait - * Call the install method using the COM RPC interface, passing the required parameters and wait - * Verify successful install by asserting that it returns Core::ERROR_NONE - * Call the PackageState method using the COM RPC interface, passing the required parameters and wait - * Verify package state method success by asserting that it returns Core::ERROR_NONE and state is 3 - INSTALLED - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, packageStateusingComRpcSuccess) { - - initforComRpc(); - - getDownloadParams(); - - uri = "https://httpbin.org/bytes/1024"; - - uint32_t timeout_ms = 3000; - - string packageId = "YouTube"; - string version = "100.1.24"; - string fileLocator = "/opt/CDL/package1001"; - Exchange::IPackageInstaller::FailReason reason = Exchange::IPackageInstaller::FailReason::NONE; - list kv = { {"testapp", "2"} }; - Exchange::IPackageInstaller::InstallState state = Exchange::IPackageInstaller::InstallState::INSTALLING; - - auto additionalMetadata = Core::Service>::Create(kv); - - EXPECT_CALL(*mSubSystemMock, IsActive(::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const PluginHost::ISubSystem::subsystem type) { - return true; - })); - - EXPECT_CALL(*mStorageManagerMock, CreateStorage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& appId, const uint32_t &size, string& path, string &errorReason) { - return Core::ERROR_NONE; - })); - - waitforSignal(TIMEOUT_FOR_INIT); - - EXPECT_EQ(Core::ERROR_NONE, pkgdownloaderInterface->Download(uri, options, downloadId)); - - EXPECT_EQ(downloadId.downloadId, "1001"); - - waitforSignal(TIMEOUT); - - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->Install(packageId, version, additionalMetadata, fileLocator, reason)); - - waitforSignal(timeout_ms); - - // TC-41: Package state using ComRpc - EXPECT_EQ(Core::ERROR_NONE, pkginstallerInterface->PackageState(packageId, version, state)); - - EXPECT_EQ(static_cast(state), 3); - - timeout_ms = 1000; - waitforSignal(timeout_ms); - - deinitforComRpc(); -} - -// IPackageHandler methods - -/* Test Case for unlock error using JsonRpc - * - * Set up and initialize required JSON-RPC resources, configurations, mocks and expectations - * Invoke the unlock method using the JSON RPC handler, passing the required parameters - * Verify unlock method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the JSON-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, unlockmethodusingJsonRpcFailure) { - - initforJsonRpc(); - - waitforSignal(TIMEOUT_FOR_INIT); - - // TC-42: Failure on unlock using JsonRpc - EXPECT_EQ(Core::ERROR_GENERAL, mJsonRpcHandler.Invoke(connection, _T("unlock"), _T("{\"packageId\": \"YouTube\", \"version\": \"100.1.24\"}"), mJsonRpcResponse)); - - deinitforJsonRpc(); -} - -/* Test Case for unlock failure using ComRpc - * - * Set up and initialize required COM-RPC resources, configurations, mocks and expectations - * Call the Unlock method using the COM RPC interface, passing required parameters - * Verify Unlock method failure by asserting that it returns Core::ERROR_GENERAL - * Deinitialize the COM-RPC resources and clean-up related test resources - */ - -TEST_F(PackageManagerTest, unlockmethodusingComRpcFailure) { - - initforComRpc(); - - string packageId = "YouTube"; - string version = "100.1.24"; - - waitforSignal(TIMEOUT_FOR_INIT); - - // TC-43: Failure on unlock using ComRpc - EXPECT_EQ(Core::ERROR_GENERAL, pkghandlerInterface->Unlock(packageId, version)); - - deinitforComRpc(); -} diff --git a/Tests/L1Tests/tests/test_PreinstallManager.cpp b/Tests/L1Tests/tests/test_PreinstallManager.cpp deleted file mode 100644 index 9a31c60..0000000 --- a/Tests/L1Tests/tests/test_PreinstallManager.cpp +++ /dev/null @@ -1,452 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include -#include -#include -#include -#include -#include - -#include "PreinstallManager.h" -#include "PreinstallManagerImplementation.h" -#include "ServiceMock.h" -#include "PackageManagerMock.h" -#include "COMLinkMock.h" -#include "ThunderPortability.h" -#include "Module.h" -#include "WorkerPoolImplementation.h" -#include "WrapsMock.h" -#include "FactoriesImplementation.h" - -extern "C" DIR* __real_opendir(const char* pathname); - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -#define PREINSTALL_MANAGER_TEST_PACKAGE_ID "com.test.preinstall.app" -#define PREINSTALL_MANAGER_TEST_VERSION "1.0.0" - -using ::testing::NiceMock; -using namespace WPEFramework; - -class PreinstallManagerTest : public ::testing::Test { -protected: - ServiceMock* mServiceMock = nullptr; - PackageInstallerMock* mPackageInstallerMock = nullptr; - WrapsImplMock *p_wrapsImplMock = nullptr; - FactoriesImplementation factoriesImplementation; - PLUGINHOST_DISPATCHER *dispatcher; - - Core::ProxyType plugin; - Plugin::PreinstallManagerImplementation *mPreinstallManagerImpl; - Exchange::IPackageInstaller::INotification* mPackageInstallerNotification_cb = nullptr; - - Core::ProxyType workerPool; - - - - Core::hresult createResources() - { - Core::hresult status = Core::ERROR_GENERAL; - mServiceMock = new NiceMock; - mPackageInstallerMock = new NiceMock; - testing::Mock::AllowLeak(mPackageInstallerMock); // Allow leak since mock lifecycle is managed by test framework - p_wrapsImplMock = new NiceMock; - Wraps::setImpl(p_wrapsImplMock); - - PluginHost::IFactories::Assign(&factoriesImplementation); - dispatcher = static_cast( - plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); - dispatcher->Activate(mServiceMock); - TEST_LOG("In createResources!"); - - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t id, const std::string& name) -> void* { - if (name == "org.rdk.PackageManagerRDKEMS") { - if (id == Exchange::IPackageInstaller::ID) { - return reinterpret_cast(mPackageInstallerMock); - } - } - return nullptr; - })); - - EXPECT_CALL(*mPackageInstallerMock, Register(::testing::_)) - .WillOnce(::testing::Invoke( - [&](Exchange::IPackageInstaller::INotification* notification) { - mPackageInstallerNotification_cb = notification; - return Core::ERROR_NONE; - })); - - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault(::testing::Return(-1)); - - EXPECT_EQ(string(""), plugin->Initialize(mServiceMock)); - mPreinstallManagerImpl = Plugin::PreinstallManagerImplementation::getInstance(); - TEST_LOG("createResources - All done!"); - status = Core::ERROR_NONE; - - return status; - } - - void releaseResources() - { - TEST_LOG("In releaseResources!"); - - if (mPackageInstallerMock != nullptr && mPackageInstallerNotification_cb != nullptr) - { - ON_CALL(*mPackageInstallerMock, Unregister(::testing::_)) - .WillByDefault(::testing::Invoke([&]() { - return 0; - })); - mPackageInstallerNotification_cb = nullptr; - } - - if (mPackageInstallerMock != nullptr) - { - EXPECT_CALL(*mPackageInstallerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mPackageInstallerMock; - return 0; - })); - } - - Wraps::setImpl(nullptr); - if (p_wrapsImplMock != nullptr) - { - delete p_wrapsImplMock; - p_wrapsImplMock = nullptr; - } - - dispatcher->Deactivate(); - dispatcher->Release(); - - plugin->Deinitialize(mServiceMock); - delete mServiceMock; - mPreinstallManagerImpl = nullptr; - } - - PreinstallManagerTest() - : plugin(Core::ProxyType::Create()), - workerPool(Core::ProxyType::Create(2, Core::Thread::DefaultStackSize(), 16)) - { - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - - virtual ~PreinstallManagerTest() override - { - TEST_LOG("Delete ~PreinstallManagerTest Instance!"); - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - } - - auto FillPackageIterator() - { - std::list packageList; - Exchange::IPackageInstaller::Package package_1; - - package_1.packageId = PREINSTALL_MANAGER_TEST_PACKAGE_ID; - package_1.version = PREINSTALL_MANAGER_TEST_VERSION; - package_1.digest = ""; - package_1.state = Exchange::IPackageInstaller::InstallState::INSTALLED; - package_1.sizeKb = 0; - - packageList.emplace_back(package_1); - return Core::Service>::Create(packageList); - } - - void SetUpPreinstallDirectoryMocks() - { - // Mock directory operations for preinstall directory - ON_CALL(*p_wrapsImplMock, opendir(::testing::_)) - .WillByDefault(::testing::Invoke([](const char* pathname) { - // Log the pathname being accessed for debugging - TEST_LOG("opendir called with pathname: %s", pathname); - return __real_opendir(pathname); - })); - - ON_CALL(*p_wrapsImplMock, readdir(::testing::_)) - .WillByDefault([](DIR* dirp) -> struct dirent* { - static int call_count = 0; - static struct dirent entry; - if (call_count == 0) { - std::strncpy(entry.d_name, "testapp", sizeof(entry.d_name) - 1); - entry.d_type = DT_DIR; - call_count++; - return &entry; - } else if (call_count == 1) { - std::strncpy(entry.d_name, "preinstallApp", sizeof(entry.d_name) - 1); - entry.d_type = DT_DIR; - call_count++; - return &entry; - } else { - call_count = 0; // Reset for next traversal - return nullptr; - } - }); - - ON_CALL(*p_wrapsImplMock, closedir(::testing::_)) - .WillByDefault([](DIR* dirp) { - // Simulate success - return 0; - }); - } -}; - -// Mock notification class using GMock -class MockNotificationTest : public Exchange::IPreinstallManager::INotification -{ -public: - MockNotificationTest() = default; - virtual ~MockNotificationTest() = default; - - MOCK_METHOD(void, OnAppInstallationStatus, (const string& jsonresponse), (override)); - MOCK_METHOD(void, AddRef, (), (const, override)); - MOCK_METHOD(uint32_t, Release, (), (const, override)); - - BEGIN_INTERFACE_MAP(MockNotificationTest) - INTERFACE_ENTRY(Exchange::IPreinstallManager::INotification) - END_INTERFACE_MAP -}; - -/*Test cases for PreinstallManager Plugin*/ -/** - * @brief Verify that PreinstallManager plugin can be created successfully - */ -TEST_F(PreinstallManagerTest, CreatePreinstallManagerPlugin) -{ - EXPECT_TRUE(plugin.IsValid()); -} - -/** - * @brief Test successful registration of notification interface - * - * @details Test verifies that: - * - Notification can be registered successfully - * - Register method returns ERROR_NONE - */ -TEST_F(PreinstallManagerTest, RegisterNotification) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - auto mockNotification = Core::ProxyType::Create(); - testing::Mock::AllowLeak(mockNotification.operator->()); // Allow leak since ProxyType manages lifecycle - Core::hresult status = mPreinstallManagerImpl->Register(mockNotification.operator->()); - - EXPECT_EQ(Core::ERROR_NONE, status); - - // Cleanup - mPreinstallManagerImpl->Unregister(mockNotification.operator->()); - releaseResources(); -} - -/** - * @brief Test successful unregistration of notification interface - * - * @details Test verifies that: - * - Notification can be unregistered successfully after registration - * - Unregister method returns ERROR_NONE - */ -TEST_F(PreinstallManagerTest, UnregisterNotification) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - auto mockNotification = Core::ProxyType::Create(); - testing::Mock::AllowLeak(mockNotification.operator->()); // Allow leak since ProxyType manages lifecycle - - // First register - Core::hresult registerStatus = mPreinstallManagerImpl->Register(mockNotification.operator->()); - EXPECT_EQ(Core::ERROR_NONE, registerStatus); - - // Then unregister - Core::hresult unregisterStatus = mPreinstallManagerImpl->Unregister(mockNotification.operator->()); - EXPECT_EQ(Core::ERROR_NONE, unregisterStatus); - - releaseResources(); -} - -/** - * @brief Test StartPreinstall with force install enabled - * - * @details Test verifies that: - * - StartPreinstall can be called with forceInstall=true - * - Method returns appropriate status - */ -TEST_F(PreinstallManagerTest, StartPreinstallWithForceInstall) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - // Mock PackageInstaller methods - EXPECT_CALL(*mPackageInstallerMock, GetConfigForPackage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string &fileLocator, string& id, string &version, WPEFramework::Exchange::RuntimeConfig &config) { - id = PREINSTALL_MANAGER_TEST_PACKAGE_ID; - version = PREINSTALL_MANAGER_TEST_VERSION; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mPackageInstallerMock, Install(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string &packageId, const string &version, - Exchange::IPackageInstaller::IKeyValueIterator* const& additionalMetadata, - const string &fileLocator, Exchange::IPackageInstaller::FailReason &failReason) { - return Core::ERROR_NONE; - }); - - SetUpPreinstallDirectoryMocks(); - - Core::hresult result = mPreinstallManagerImpl->StartPreinstall(true); - - // The result can be ERROR_NONE or ERROR_GENERAL depending on directory existence - // We mainly test that the method doesn't crash - EXPECT_TRUE(result == Core::ERROR_NONE || result == Core::ERROR_GENERAL); - - releaseResources(); -} - -/** - * @brief Test StartPreinstall with force install disabled - * - * @details Test verifies that: - * - StartPreinstall can be called with forceInstall=false - * - Method checks existing packages before installing - */ -TEST_F(PreinstallManagerTest, StartPreinstallWithoutForceInstall) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - // Mock ListPackages to return existing packages - EXPECT_CALL(*mPackageInstallerMock, ListPackages(::testing::_)) - .WillRepeatedly([&](Exchange::IPackageInstaller::IPackageIterator*& packages) { - auto mockIterator = FillPackageIterator(); - packages = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_CALL(*mPackageInstallerMock, GetConfigForPackage(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([&](const string &fileLocator, string& id, string &version, WPEFramework::Exchange::RuntimeConfig &config) { - id = PREINSTALL_MANAGER_TEST_PACKAGE_ID; - version = PREINSTALL_MANAGER_TEST_VERSION; - return Core::ERROR_NONE; - }); - - SetUpPreinstallDirectoryMocks(); - - Core::hresult result = mPreinstallManagerImpl->StartPreinstall(false); - - // The result can be ERROR_NONE or ERROR_GENERAL depending on directory existence - EXPECT_TRUE(result == Core::ERROR_NONE || result == Core::ERROR_GENERAL); - - releaseResources(); -} - -/** - * @brief Test StartPreinstall failure when PackageManager object creation fails - * - * @details Test verifies that: - * - StartPreinstall returns ERROR_GENERAL when PackageManager is not available - */ -TEST_F(PreinstallManagerTest, StartPreinstallFailsWhenPackageManagerUnavailable) -{ - // Create minimal setup without PackageManager mock - mServiceMock = new NiceMock; - - // Don't set up PackageInstaller mock in QueryInterfaceByCallsign - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(nullptr)); - - EXPECT_EQ(string(""), plugin->Initialize(mServiceMock)); - mPreinstallManagerImpl = Plugin::PreinstallManagerImplementation::getInstance(); - - Core::hresult result = mPreinstallManagerImpl->StartPreinstall(true); - - EXPECT_EQ(Core::ERROR_GENERAL, result); - - plugin->Deinitialize(mServiceMock); - delete mServiceMock; - mPreinstallManagerImpl = nullptr; -} - -/** - * @brief Test notification handling for app installation status - * - * @details Test verifies that: - * - Notification callbacks are properly triggered - * - Installation status is handled correctly - */ -TEST_F(PreinstallManagerTest, HandleAppInstallationStatusNotification) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - auto mockNotification = Core::ProxyType::Create(); - testing::Mock::AllowLeak(mockNotification.operator->()); // Allow leak since ProxyType manages lifecycle - - // Use a promise/future to wait for the asynchronous notification - std::promise notificationPromise; - std::future notificationFuture = notificationPromise.get_future(); - - // Expect the notification method to be called and signal completion - EXPECT_CALL(*mockNotification, OnAppInstallationStatus(::testing::_)) - .Times(1) - .WillOnce(::testing::InvokeWithoutArgs([¬ificationPromise]() { - notificationPromise.set_value(); - })); - - mPreinstallManagerImpl->Register(mockNotification.operator->()); - - // Simulate installation status notification - string testJsonResponse = R"({"packageId":"testApp","version":"1.0.0","status":"SUCCESS"})"; - - // Call the handler directly since it's a friend class - mPreinstallManagerImpl->handleOnAppInstallationStatus(testJsonResponse); - - // Wait for the asynchronous notification (with timeout) - auto status = notificationFuture.wait_for(std::chrono::seconds(2)); - EXPECT_EQ(std::future_status::ready, status) << "Notification was not received within timeout"; - - // Cleanup - mPreinstallManagerImpl->Unregister(mockNotification.operator->()); - releaseResources(); -} - -/** - * @brief Test QueryInterface functionality - * - * @details Test verifies that: - * - QueryInterface returns proper interfaces - * - IPreinstallManager interface can be obtained - */ -TEST_F(PreinstallManagerTest, QueryInterface) -{ - ASSERT_EQ(Core::ERROR_NONE, createResources()); - - // Test querying IPreinstallManager interface - Exchange::IPreinstallManager* preinstallInterface = - static_cast( - mPreinstallManagerImpl->QueryInterface(Exchange::IPreinstallManager::ID)); - - EXPECT_TRUE(preinstallInterface != nullptr); - - if (preinstallInterface != nullptr) { - preinstallInterface->Release(); - } - - releaseResources(); -} diff --git a/Tests/L1Tests/tests/test_RDKShell.cpp b/Tests/L1Tests/tests/test_RDKShell.cpp deleted file mode 100644 index 519e129..0000000 --- a/Tests/L1Tests/tests/test_RDKShell.cpp +++ /dev/null @@ -1,874 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef USE_THUNDER_R4 /* Needs RDK-51642 changes for R4.4.1*/ -#include -#include -#include "RDKShell.h" -#include "rdkshell.h" -#include "rdkshellmock.h" -#include "ServiceMock.h" -#include "ThunderPortability.h" - -using namespace WPEFramework; - -class RDKShellTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - DECL_CORE_JSONRPC_CONX connection; - Core::JSONRPC::Message message; - RDKShellImplMock *p_rdkShellImplMock = nullptr ; - CompositorImplMock *p_compositorImplMock = nullptr ; - RdkShellApiImplMock *p_rdkShellApiImplMock = nullptr ; - string response; - - RDKShellTest() - : plugin(Core::ProxyType::Create()) - , handler(*(plugin)) - , INIT_CONX(1, 0) - { - p_rdkShellApiImplMock = new testing::NiceMock ; - RdkShell::RdkShellApi::setImpl(p_rdkShellApiImplMock); - - p_compositorImplMock = new testing::NiceMock ; - RdkShell::CompositorController::setImpl(p_compositorImplMock); - - p_rdkShellImplMock = new testing::NiceMock ; - RDKShell::setImpl(p_rdkShellImplMock); - } - virtual ~RDKShellTest() - { - RdkShell::RdkShellApi::setImpl(nullptr); - if (p_rdkShellApiImplMock != nullptr) - { - delete p_rdkShellApiImplMock; - p_rdkShellApiImplMock = nullptr; - } - - RDKShell::setImpl(nullptr); - if (p_rdkShellImplMock != nullptr) - { - delete p_rdkShellImplMock; - p_rdkShellImplMock = nullptr; - } - RdkShell::CompositorController::setImpl(nullptr); - if (p_compositorImplMock != nullptr) - { - delete p_compositorImplMock; - p_compositorImplMock = nullptr; - } - } -}; - - -TEST_F(RDKShellTest, RegisteredMethods){ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addAnimation"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addKeyIntercept"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addKeyIntercepts"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addKeyListener"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addKeyMetadataListener"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("exitAgingMode"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("createDisplay"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("destroy"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableInactivityReporting"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableKeyRepeats"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableLogsFlushing"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableVirtualDisplay"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("generateKey"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getAvailableTypes"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getBounds"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getClients"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getCursorSize"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getHolePunch"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getKeyRepeatsEnabled"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getLastWakeupKey"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getLogsFlushingEnabled"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getOpacity"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getScale"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getScreenResolution"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getScreenshot"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getState"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getSystemMemory"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getSystemResourceInfo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getVirtualDisplayEnabled"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getVirtualResolution"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getVisibility"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getZOrder"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getGraphicsFrameRate"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("hideAllClients"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("hideCursor"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("hideFullScreenImage"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("hideSplashLogo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("ignoreKeyInputs"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("injectKey"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("kill"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("launch"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("launchApplication"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("launchResidentApp"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("moveBehind"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("moveToBack"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("moveToFront"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("removeAnimation"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("removeKeyIntercept"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("removeKeyListener"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("removeKeyMetadataListener"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("resetInactivityTime"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("resumeApplication"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("scaleToFit"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setBounds"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setCursorSize"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setFocus"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setHolePunch"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setInactivityInterval"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setLogLevel"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setMemoryMonitor"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setOpacity"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setScale"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setScreenResolution"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setTopmost"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setVirtualResolution"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setVisibility"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setGraphicsFrameRate"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("showCursor"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("showFullScreenImage"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("showSplashLogo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("showWatermark"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("suspend"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("suspendApplication"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("keyRepeatConfig"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setAVBlocked"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getBlockedAVApplications"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("addEasterEggs"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("removeEasterEggs"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableEasterEggs"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getEasterEggs"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("launchFactoryApp"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("launchFactoryAppShortcut"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("enableInputEvents"))); - } -TEST_F(RDKShellTest, enableInputEvents) -{ - ON_CALL(*p_compositorImplMock, enableInputEvents(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, bool enable){ - EXPECT_EQ(client, string("searchanddiscovery")); - EXPECT_EQ(enable, true); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("enableInputEvents"), _T("{" - "\"clients\": [" - " \"searchanddiscovery\"" - "]," - "\"enable\": true" - "}"), response)); -} - -TEST_F(RDKShellTest, getClients) -{ - ON_CALL(*p_compositorImplMock, getClients(::testing::_)) - .WillByDefault(::testing::Invoke( - [](std::vector& clients){ - clients.push_back("org.rdk.Netflix"); - clients.push_back("org.rdk.RDKBrowser2"); - clients.push_back("Test1"); - clients.push_back("Test2"); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getClients"), _T("{}"), response)); - EXPECT_EQ(response, string("{" - "\"clients\":[" - "\"org.rdk.Netflix\"," - "\"org.rdk.RDKBrowser2\"," - "\"Test1\"," - "\"Test2\"" - "]," - "\"success\":true" - "}")); -} - -TEST_F(RDKShellTest, keyRepeatConfig) -{ - ON_CALL(*p_compositorImplMock, setKeyRepeatConfig(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](bool enabled, int32_t initialDelay, int32_t repeatInterval){ - EXPECT_EQ(enabled, true); - EXPECT_EQ(initialDelay, 500); - EXPECT_EQ(repeatInterval, 250); - return true; - })); - - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("keyRepeatConfig"), _T("{" - "\"enabled\":true," - "\"initialDelay\":500," - "\"repeatInterval\":250}"), response)); -} - -TEST_F(RDKShellTest, resetinactivity) -{ - ON_CALL(*p_compositorImplMock, resetInactivityTime()) - .WillByDefault(::testing::Invoke( - [&](){ - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("resetInactivityTime"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, launchApplication) -{ - ON_CALL(*p_compositorImplMock, launchApplication(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const std::string& uri, const std::string& mimeType, bool topmost, bool focus){ - EXPECT_EQ(client, string("testApp")); - EXPECT_EQ(uri, string("/usr/bin/westeros_test")); - EXPECT_EQ(mimeType, string("application/native")); - EXPECT_EQ(topmost, false); - EXPECT_EQ(focus, false); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("launchApplication"), _T("{\"client\": \"testApp\"," - "\"uri\": \"/usr/bin/westeros_test\"," - "\"mimeType\": \"application/native\"}"), response)); -} - -TEST_F(RDKShellTest, suspendApplication) -{ - ON_CALL(*p_compositorImplMock, suspendApplication(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client){ - EXPECT_EQ(client, string("HtmlApp")); - return true; - })); - ON_CALL(*p_compositorImplMock, setVisibility(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool visible){ - EXPECT_EQ(client, string("HtmlApp")); - EXPECT_EQ(visible, false); - return true; - })); - ON_CALL(*p_compositorImplMock, getMimeType(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const string& client, string& mimeType){ - mimeType = RDKSHELL_APPLICATION_MIME_TYPE_NATIVE; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("suspendApplication"), _T("{\"client\": \"HtmlApp\"}"), response)); -} - -TEST_F(RDKShellTest, resumeApplication) -{ - ON_CALL(*p_compositorImplMock, resumeApplication(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client){ - EXPECT_EQ(client, string("HtmlApp")); - return true; - })); - ON_CALL(*p_compositorImplMock, setVisibility(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool visible){ - EXPECT_EQ(client, string("HtmlApp")); - EXPECT_EQ(visible, true); - return true; - })); - ON_CALL(*p_compositorImplMock, getMimeType(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const string& client, string& mimeType){ - mimeType = RDKSHELL_APPLICATION_MIME_TYPE_NATIVE; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("resumeApplication"), _T("{\"client\": \"HtmlApp\"}"), response)); -} - - -TEST_F(RDKShellTest, getGraphicsFrameRate) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getGraphicsFrameRate"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"framerate\":40,\"success\":true}")); -} - -TEST_F(RDKShellTest, setGraphicsFrameRate) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setGraphicsFrameRate"), _T("{\"framerate\":60}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, showFullScreenImage) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("showFullScreenImage"), _T("{\"path\":\"tmp\netflix.png\"}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, hideFullScreenImage) -{ - ON_CALL(*p_compositorImplMock, hideFullScreenImage()) - .WillByDefault(::testing::Return(true)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("hideFullScreenImage"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, setvisibility) -{ - ON_CALL(*p_compositorImplMock, setVisibility(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool visible){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(visible, true); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setVisibility"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"," - "\"visible\": true}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, getVisibility) -{ - ON_CALL(*p_compositorImplMock, getVisibility(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, bool& visible){ - bool x = true; - visible = x; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getVisibility"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"visible\":true,\"success\":true}")); -} - -TEST_F(RDKShellTest, getSystemMemory) -{ - EXPECT_CALL(*p_rdkShellApiImplMock, systemRam(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](uint32_t& freeKb, uint32_t& totalKb, uint32_t& availableKb, uint32_t& usedSwapKb) { - freeKb = 994056; - totalKb = 2830092; - usedSwapKb = 0; - availableKb = 764628; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getSystemMemory"), _T("{}"), response)); - EXPECT_EQ(response, string("{" - "\"freeRam\":994056," - "\"swapRam\":0," - "\"totalRam\":2830092," - "\"availablememory\":764628," - "\"success\":true" - "}")); -} - - -TEST_F(RDKShellTest, setBounds) -{ - ON_CALL(*p_compositorImplMock, setBounds(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(x, 0); - EXPECT_EQ(y, 0); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setBounds"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\",\"x\":0,\"y\":0,\"w\":1920,\"h\":1080}"),response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} -TEST_F(RDKShellTest, getBounds) -{ - ON_CALL(*p_compositorImplMock, getBounds(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, uint32_t &x, uint32_t &y, uint32_t &width, uint32_t &height){ - x = 0; - y = 0; - width = 1920; - height = 1080; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getBounds"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{" - "\"bounds\":{" - "\"x\":0," - "\"y\":0," - "\"w\":1920," - "\"h\":1080" - "}," - "\"success\":true" - "}")); -} - -TEST_F(RDKShellTest, setCursorSize) -{ - ON_CALL(*p_compositorImplMock, setCursorSize(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](uint32_t width, uint32_t height){ - EXPECT_EQ(width, 255); - EXPECT_EQ(height, 255); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setCursorSize"), _T("{\"width\":255,\"height\":255}"),response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} -TEST_F(RDKShellTest, getCursorSize) -{ - ON_CALL(*p_compositorImplMock, getCursorSize(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](uint32_t& width, uint32_t& height){ - width = 255; - height = 255; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getCursorSize"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"width\":255,\"height\":255,\"success\":true}")); -} - -TEST_F(RDKShellTest, showCursor) -{ - ON_CALL(*p_compositorImplMock, showCursor()) - .WillByDefault(::testing::Return(true)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("showCursor"), _T("{}"),response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} -TEST_F(RDKShellTest, hideCursor) -{ - ON_CALL(*p_compositorImplMock, hideCursor()) - .WillByDefault(::testing::Return(true)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("hideCursor"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, setLogLevel) -{ - ON_CALL(*p_compositorImplMock, setLogLevel(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string level){ - EXPECT_EQ(level, string("DEBUG")); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setLogLevel"), _T("{\"logLevel\": \"DEBUG\"}"), response)); -} - -TEST_F(RDKShellTest, getLogLevel) -{ - ON_CALL(*p_compositorImplMock, getLogLevel(::testing::_)) - .WillByDefault(::testing::Invoke( - [](std::string& level){ - std::string a = "DEBUG"; - level = a; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getLogLevel"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"logLevel\":\"DEBUG\",\"success\":true}")); -} - - - -TEST_F(RDKShellTest, enablekeyRepeat) -{ - ON_CALL(*p_compositorImplMock, enableKeyRepeats(::testing::_)) - .WillByDefault(::testing::Invoke( - [](bool enable){ - EXPECT_EQ(enable, true); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("enableKeyRepeats"), _T("{\"enable\":true}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, getKeyRepeatsEnabled) -{ - ON_CALL(*p_compositorImplMock, getKeyRepeatsEnabled(::testing::_)) - .WillByDefault(::testing::Invoke( - [](bool& enable){ - enable = true; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getKeyRepeatsEnabled"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"keyRepeat\":true,\"success\":true}")); -} - -TEST_F(RDKShellTest, setScreenResolution) -{ - ON_CALL(*p_compositorImplMock, setScreenResolution(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const uint32_t width, const uint32_t height){ - EXPECT_EQ(width, 1920); - EXPECT_EQ(height, 1080); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setScreenResolution"), _T("{\"w\":1920,\"h\":1080}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} -TEST_F(RDKShellTest, getScreenResolution) -{ - ON_CALL(*p_compositorImplMock, getScreenResolution(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](uint32_t &width, uint32_t &height){ - width = 1920; - height = 1080; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getScreenResolution"), _T("{}"), response)); - EXPECT_EQ(response, _T("{\"w\":1920,\"h\":1080,\"success\":true}")); -} - -TEST_F(RDKShellTest, setVirtualResolution) -{ - ON_CALL(*p_compositorImplMock, setVirtualResolution(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const uint32_t virtualWidth, const uint32_t virtualHeight){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(virtualWidth, 1920); - EXPECT_EQ(virtualHeight, 1080); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setVirtualResolution"), _T("{\"client\":\"org.rdk.Netflix\",\"width\":1920,\"height\":1080}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, getVirtualResolution) -{ - ON_CALL(*p_compositorImplMock, getVirtualResolution(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, uint32_t &virtualWidth, uint32_t &virtualHeight){ - virtualWidth = 1920; - virtualHeight = 1080; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getVirtualResolution"), _T("{\"client\":\"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, _T("{\"width\":1920,\"height\":1080,\"success\":true}")); -} - - -TEST_F(RDKShellTest, ScaleToFit) -{ - ON_CALL(*p_compositorImplMock, scaleToFit(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const int32_t x, const int32_t y, const uint32_t width, const uint32_t height){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(x, 0); - EXPECT_EQ(y, 0); - EXPECT_EQ(width, 1920); - EXPECT_EQ(height, 1080); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("scaleToFit"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"," - "\"x\":0,\"y\":0,\"w\":1920,\"h\":1080}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); - -} - - -TEST_F(RDKShellTest, hideAllClients) -{ - ON_CALL(*p_compositorImplMock, getClients(::testing::_)) - .WillByDefault(::testing::Invoke( - [](std::vector& clients){ - clients.push_back("org.rdk.Netflix"); - clients.push_back("org.rdk.RDKBrowser2"); - clients.push_back("Test1"); - clients.push_back("Test2"); - return true; - })); - ON_CALL(*p_compositorImplMock, setVisibility(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool visible){ - EXPECT_EQ(visible, false); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("hideAllClients"), _T("{\"hide\":true}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, ignoreKeyInputs) -{ - ON_CALL(*p_compositorImplMock, ignoreKeyInputs(::testing::_)) - .WillByDefault(::testing::Invoke( - [](bool ignore){ - EXPECT_EQ(ignore, false); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("ignoreKeyInputs"), _T("{\"ignore\":false}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - - -TEST_F(RDKShellTest, moveToFront) -{ - ON_CALL(*p_compositorImplMock, moveToFront(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client) { - EXPECT_EQ(client, string("org.rdk.Netflix")); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("moveToFront"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); - -} - -TEST_F(RDKShellTest, moveToBack) -{ - ON_CALL(*p_compositorImplMock, moveToBack(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client) { - EXPECT_EQ(client, string("org.rdk.Netflix")); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("moveToBack"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, moveBehind) -{ - ON_CALL(*p_compositorImplMock, moveBehind(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const std::string& target) { - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(target, string("org.rdk.RDKBrowser2")); - return true; - })); - ON_CALL(*p_compositorImplMock, getClients(::testing::_)) - .WillByDefault(::testing::Invoke( - [](std::vector& clients){ - clients.push_back("org.rdk.Netflix"); - clients.push_back("org.rdk.RDKBrowser2"); - clients.push_back("Test2"); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("moveBehind"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"target\": \"org.rdk.RDKBrowser2\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); - -} - -TEST_F(RDKShellTest, getOpacity) -{ - ON_CALL(*p_compositorImplMock, getOpacity(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, unsigned int& opacity) { - opacity = 100; - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getOpacity"), _T("{\"client\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"opacity\":100,\"success\":true}")); -} - - -TEST_F(RDKShellTest, setFocus) -{ - ON_CALL(*p_compositorImplMock, setFocus(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setFocus"), _T("{\"client\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, removeKeyIntercepts) -{ - ON_CALL(*p_compositorImplMock, removeKeyIntercept(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const uint32_t& keyCode, const uint32_t& flags){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(keyCode, 10); - EXPECT_EQ(flags, RDKSHELL_FLAGS_SHIFT); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("removeKeyIntercept"), _T("{" - "\"keyCode\": 10," - "\"modifiers\": [" - " \"shift\"" - "]," - "\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"" - "}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, removeKeyListeners) -{ - ON_CALL(*p_compositorImplMock, removeKeyListener(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const uint32_t& keyCode, const uint32_t& flags){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(keyCode, 10); - EXPECT_EQ(flags, RDKSHELL_FLAGS_SHIFT); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("removeKeyListener"), _T("{" - "\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"," - "\"keys\": [" - "{" - "\"keyCode\": 10," - "\"nativekeyCode\": 10," - "\"modifiers\": [" - "\"shift\"" - "]," - "\"activate\": false," - "\"propagate\": true" - "}" - "]" - "}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, removeKeyMetadataListener) -{ - ON_CALL(*p_compositorImplMock, removeKeyMetadataListener(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("removeKeyMetadataListener"), _T("{\"client\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); -} - -TEST_F(RDKShellTest, injectKey) -{ - ON_CALL(*p_compositorImplMock, injectKey(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const uint32_t& keyCode, const uint32_t& flags) { - EXPECT_EQ(keyCode, 10); - EXPECT_EQ(flags, RDKSHELL_FLAGS_SHIFT); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("injectKey"), _T("{\"keyCode\": 10, \"modifiers\": [\"shift\"]}"), response)); -} - -TEST_F(RDKShellTest, getZOrder) -{ - ON_CALL(*p_compositorImplMock, getZOrder(::testing::_)) - .WillByDefault(::testing::Invoke( - [](std::vector& clients){ - clients.push_back("org.rdk.Netflix"); - clients.push_back("org.rdk.RDKBrowser2"); - clients.push_back("Test1"); - clients.push_back("Test2"); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getZOrder"), _T("{}"), response)); - EXPECT_EQ(response, string("{" - "\"clients\":[" - "\"org.rdk.Netflix\"," - "\"org.rdk.RDKBrowser2\"," - "\"Test1\"," - "\"Test2\"" - "]," - "\"success\":true" - "}")); -} - -TEST_F(RDKShellTest, setHolePunch) -{ - ON_CALL(*p_compositorImplMock, setHolePunch(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool holePunch){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(holePunch, true); - return true; - })); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setHolePunch"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"," - "\"holePunch\": true}"), response)); - EXPECT_EQ(response, string("{\"success\":true}")); - -} - -TEST_F(RDKShellTest, getHolePunch) -{ - ON_CALL(*p_compositorImplMock, getHolePunch(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, bool& holePunch){ - holePunch = true; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getHolePunch"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); - EXPECT_EQ(response, string("{\"holePunch\":true,\"success\":true}")); - - -} - -TEST_F(RDKShellTest, getScale) -{ - ON_CALL(*p_compositorImplMock, getScale(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, double &scaleX, double &scaleY){ - scaleX = 1.0; - scaleY = 1.0; - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getScale"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"}"), response)); -} - - -TEST_F(RDKShellTest, enableVirtualDisplay) -{ - ON_CALL(*p_compositorImplMock, enableVirtualDisplay(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](const std::string& client, const bool enable){ - EXPECT_EQ(client, string("org.rdk.Netflix")); - EXPECT_EQ(enable, true); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("enableVirtualDisplay"), _T("{\"client\": \"org.rdk.Netflix\"," - "\"callsign\": \"org.rdk.Netflix\"," - "\"enable\": true}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} - -TEST_F(RDKShellTest, enableInactivityReporting) -{ - ON_CALL(*p_compositorImplMock, enableInactivityReporting(::testing::_)) - .WillByDefault(::testing::Invoke( - [](const bool enable){ - EXPECT_EQ(enable, true); - return true; - })); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("enableInactivityReporting"), _T("{\"enable\": true}"), response)); - EXPECT_EQ(response, _T("{\"success\":true}")); -} -#endif /* !USE_THUNDER_R4 */ diff --git a/Tests/L1Tests/tests/test_ResourceManager.cpp b/Tests/L1Tests/tests/test_ResourceManager.cpp deleted file mode 100644 index 2fb3843..0000000 --- a/Tests/L1Tests/tests/test_ResourceManager.cpp +++ /dev/null @@ -1,230 +0,0 @@ - -#include -#include - -#include "ResourceManager.h" -#include "ServiceMock.h" -#include -#include "ThunderPortability.h" - -using namespace WPEFramework; -using ::testing::NiceMock; -using ::testing::Return; -using ::testing::_; -using ::testing::DoAll; -using ::testing::SetArgReferee; -using std::string; - -// ===== Testable Wrapper Class ===== -class TestableResourceManagerPlugin : public Plugin::ResourceManager { -public: - void setDisableReserveTTS(bool value) { - mDisableReserveTTS = value; - } - - bool callSetAVBlocked(const std::string& client, bool blocked) { - return setAVBlocked(client, blocked); -} - - bool getBlockedAVApplicationsPublic(std::vector& appsList) { - return getBlockedAVApplications(appsList); - } - -}; - -// ===== Test Fixture Base ===== -class ResourceManagerTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - DECL_CORE_JSONRPC_CONX connection; - string response; - - ResourceManagerTest() - : plugin(Core::ProxyType::Create()) - , handler(*plugin) - , INIT_CONX(1, 0) - {} - - virtual ~ResourceManagerTest() = default; -}; - -// ===== Mock for SecurityAgent ===== -class MockAuthenticate : public PluginHost::IAuthenticate { -public: - MOCK_METHOD(uint32_t, CreateToken, (const uint16_t length, const uint8_t buffer[], std::string& token), (override)); - MOCK_METHOD(PluginHost::ISecurity*, Officer, (const std::string& token), (override)); - MOCK_METHOD(uint32_t, Release, (), (const, override)); - MOCK_METHOD(void, AddRef, (), (const, override)); - - BEGIN_INTERFACE_MAP(MockAuthenticate) - INTERFACE_ENTRY(PluginHost::IAuthenticate) - END_INTERFACE_MAP -}; - -// ===== Derived Fixture with Initialized Plugin ===== -class ResourceManagerInitializedTest : public ResourceManagerTest { -protected: - NiceMock service; - NiceMock* mockAuth = nullptr; - -public: - ResourceManagerInitializedTest() { - mockAuth = new NiceMock(); - - ON_CALL(service, QueryInterfaceByCallsign(_, _)) - .WillByDefault([this](const uint32_t, const std::string& name) -> void* { - if (name == "SecurityAgent") { - mockAuth->AddRef(); - return static_cast(mockAuth); - } - return nullptr; - }); - - plugin->Initialize(&service); - } - - ~ResourceManagerInitializedTest() override { - plugin->Deinitialize(&service); - delete mockAuth; - } -}; - -// ========================= -// ===== TEST CASES ======== -// ========================= - -TEST_F(ResourceManagerInitializedTest, InitializeGetsSecurityToken) -{ - EXPECT_CALL(*mockAuth, CreateToken(_, _, _)) - .WillOnce(DoAll(SetArgReferee<2>("mocked_token"), Return(Core::ERROR_NONE))); - - EXPECT_CALL(*mockAuth, Release()).Times(1); - - EXPECT_EQ("", plugin->Initialize(&service)); -} - -TEST_F(ResourceManagerInitializedTest, InitializeFailsToGetToken) -{ - EXPECT_CALL(*mockAuth, CreateToken(_, _, _)) - .WillOnce(Return(Core::ERROR_GENERAL)); - - EXPECT_CALL(*mockAuth, Release()).Times(1); - - EXPECT_EQ("", plugin->Initialize(&service)); -} - -TEST_F(ResourceManagerTest, InitializeWithoutSecurityAgent) -{ - NiceMock noSecurityService; - - ON_CALL(noSecurityService, QueryInterfaceByCallsign(_, _)) - .WillByDefault(Return(nullptr)); - - EXPECT_EQ("", plugin->Initialize(&noSecurityService)); -} - -TEST_F(ResourceManagerInitializedTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setAVBlocked"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("reserveTTSResource"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getBlockedAVApplications"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("reserveTTSResourceForApps"))); - -} - -TEST_F(ResourceManagerInitializedTest, SetAVBlockedTest) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setAVBlocked"), - _T("{\"appid\":\"testApp\",\"blocked\":true}"), response)); -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResourceTest_1) -{ - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResource"), - _T("{\"appid\":\"testApp\"}"), response)); -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResourceForAppsTest_1) -{ - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResourceForApps"), - _T("{\"appids\":[\"testApp1\",\"testApp2\"]}"), response)); -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResourceTest_3) -{ - plugin->Deinitialize(&service); - plugin->Initialize(&service); - - plugin->setDisableReserveTTS(true); - - std::cout << "[TEST] tiwarisetDisableReserveTTS(true) called\n"; - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResource"), - _T("{ \"appid\": \"testApp\" }"), response)); - -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResourceForAppsTest_3) -{ - plugin->Deinitialize(&service); - plugin->Initialize(&service); - - plugin->setDisableReserveTTS(true); - - std::cout << "[TEST] tiwarisetDisableReserveTTS(true) called\n"; - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResourceForApps"), - _T("{ \"appids\": [\"testApp1\",\"testApp2\"]}"), response)); - -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResource_MissingAppId) -{ - plugin->Deinitialize(&service); - plugin->Initialize(&service); - - plugin->setDisableReserveTTS(false); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResource"), - _T("{ }"), response)); -} - -TEST_F(ResourceManagerInitializedTest, ReserveTTSResourceForApps_MissingAppIds) -{ - plugin->Deinitialize(&service); - plugin->Initialize(&service); - - plugin->setDisableReserveTTS(false); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("reserveTTSResourceForApps"), - _T("{ }"), response)); -} - -TEST_F(ResourceManagerInitializedTest, InformationReturnsEmptyStringTest) -{ - EXPECT_EQ("", plugin->Information()); -} -TEST_F(ResourceManagerInitializedTest, getBlockedAVApplicationsTest_1) -{ - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getBlockedAVApplications"), _T("{}"), response)); -} - -TEST_F(ResourceManagerInitializedTest, GetBlockedAVApplicationsTest_1) -{ - std::vector expectedAppsList = {"App1", "App2", "App3"}; - - plugin->getBlockedAVApplicationsPublic(expectedAppsList); - - ASSERT_EQ(expectedAppsList.size(), 3); - EXPECT_EQ(expectedAppsList[0], "App1"); - EXPECT_EQ(expectedAppsList[1], "App2"); - EXPECT_EQ(expectedAppsList[2], "App3"); -} - -TEST_F(ResourceManagerInitializedTest, SetAVBlockedInternalTest) -{ - bool result = plugin->callSetAVBlocked("testApp", true); - EXPECT_TRUE(result); -} - diff --git a/Tests/L1Tests/tests/test_RunTimeManager.cpp b/Tests/L1Tests/tests/test_RunTimeManager.cpp deleted file mode 100755 index 2a6e68c..0000000 --- a/Tests/L1Tests/tests/test_RunTimeManager.cpp +++ /dev/null @@ -1,1542 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#include -#include - -#include "RuntimeManager.h" -#include "RuntimeManagerImplementation.h" -#include "HostMock.h" -#include "ServiceMock.h" -#include "ThunderPortability.h" -#include "StorageManagerMock.h" -#include "COMLinkMock.h" -#include "OCIContainerMock.h" -#include "WindowManagerMock.h" -#include "WorkerPoolImplementation.h" -#include - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define TEST_APP_CONTAINER_ID "com.sky.as.appsyouTube" - -using namespace WPEFramework; -using ::testing::NiceMock; - -class RuntimeManagerTest : public ::testing::Test { -protected: - string response; - Core::ProxyType mRuntimeManagerImpl; - Exchange::IRuntimeManager* interface = nullptr; - Exchange::IConfiguration* runTimeManagerConfigure = nullptr; - ServiceMock *mServiceMock = nullptr; - StorageManagerMock* mStoreageManagerMock = nullptr; - OCIContainerMock* mociContainerMock = nullptr; - WindowManagerMock* mWindowManagerMock = nullptr; - Core::ProxyType workerPool; - - RuntimeManagerTest() - : workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)) - { - // create the RuntimeManagerImplementation instance - mRuntimeManagerImpl = Core::ProxyType::Create(); - - interface = static_cast( - mRuntimeManagerImpl->QueryInterface(Exchange::IRuntimeManager::ID)); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - } - virtual ~RuntimeManagerTest() - { - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - - interface->Release(); - } - - bool createResources(void) - { - mStoreageManagerMock = new NiceMock; - mociContainerMock = new NiceMock; - mWindowManagerMock = new NiceMock; - mServiceMock = new NiceMock; - - runTimeManagerConfigure = static_cast( - mRuntimeManagerImpl->QueryInterface(Exchange::IConfiguration::ID)); - - EXPECT_CALL(*mServiceMock, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t, const std::string& name) -> void* { - if (name == "org.rdk.StorageManager") { - return reinterpret_cast(mStoreageManagerMock); - } - else if (name == "org.rdk.OCIContainer") { - return reinterpret_cast(mociContainerMock); - } - else if (name == "org.rdk.RDKWindowManager") { - return reinterpret_cast(mWindowManagerMock); - } - return nullptr; - })); - - EXPECT_CALL(*mWindowManagerMock, AddRef()) - .Times(::testing::AnyNumber()); - - EXPECT_CALL(*mWindowManagerMock, Register(::testing::_)) - .WillRepeatedly(::testing::Return(Core::ERROR_NONE)); - - // Mock ConfigLine to return the runtime app portal configuration - ON_CALL(*mServiceMock, ConfigLine()) - .WillByDefault(::testing::Return("{\"runtimeAppPortal\":\"com.sky.as.apps\"}")); - - runTimeManagerConfigure->Configure(mServiceMock); - return true; - } - - void releaseResources() - { - // Clean up mocks - if (mociContainerMock != nullptr) - { - EXPECT_CALL(*mociContainerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mociContainerMock; - return 0; - })); - } - - if (mServiceMock != nullptr) - { - EXPECT_CALL(*mServiceMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mServiceMock; - return 0; - })); - } - - if (mStoreageManagerMock != nullptr) - { - EXPECT_CALL(*mStoreageManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mStoreageManagerMock; - return 0; - })); - } - - if (mWindowManagerMock != nullptr) - { - EXPECT_CALL(*mWindowManagerMock, Release()) - .WillOnce(::testing::Invoke( - [&]() { - delete mWindowManagerMock; - return 0; - })); - } - - runTimeManagerConfigure->Release(); - } - - virtual void SetUp() - { - ASSERT_TRUE(interface != nullptr); - } - - virtual void TearDown() - { - ASSERT_TRUE(interface != nullptr); - } -}; - -/* Test Case for TerminateMethods - * - * Setting up Runtime Manager Plugin and creating required COM-RPC resources - * Simulating a container instance for the given appInstanceId ("youTube") - * Setting up a mock expectation on StopContainer() to simulate graceful termination - * Verifying Terminate() method sends stop request for the container with correct parameters - * Simulating successful termination response via mocked StopContainer() implementation - * Asserting that Terminate() returns Core::ERROR_NONE upon successful termination - * Releasing the Runtime Manager Interface object and associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateMethods) -{ - string appInstanceId("youTube"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, false,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool force, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Terminate(appInstanceId)); - releaseResources(); -} - -/* Test Case for TerminateFailsWithEmptyAppInstanceId - * - * Setting up Runtime Manager Plugin and creating required COM-RPC resources - * Attempting to terminate a container using an empty appInstanceId ("") - * Setting up a mock expectation on StopContainer(), though it should not be invoked - * Verifying Terminate() method properly handles invalid (empty) input - * Simulating that the call returns Core::ERROR_GENERAL due to missing appInstanceId - * Asserting that Terminate() fails early without attempting container interaction - * Releasing the Runtime Manager Interface object and associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, false,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool force, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Terminate(appInstanceId)); - releaseResources(); -} - -/* Test Case for TerminateNonExistentContainer - * - * Setting up Runtime Manager Plugin and creating required COM-RPC resources - * Attempting to terminate a container using a non-existent appInstanceId ("invalid_id") - * Setting up a mock expectation on StopContainer() to simulate failure due to missing container - * Simulating StopContainer() returning success = false and an errorReason indicating container not found - * Verifying that Terminate() still returns Core::ERROR_NONE as the request was processed, even if container didn't exist - * Asserting graceful handling of termination requests for non-existent containers - * Releasing the Runtime Manager Interface object and associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateNonExistentContainer) { - - string appInstanceId("invalid_id"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StopContainer(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "Container not found"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_NONE, interface->Terminate(appInstanceId)); - releaseResources(); -} - -/* Test Case for TerminateWithInvalidContainerId - * - * Setting up Runtime Manager Plugin and creating required COM-RPC resources - * Using an intentionally malformed or invalid appInstanceId ("_567gshg&*rt-") - * Expecting the StopContainer() method to be invoked with this invalid ID - * Simulating failure in StopContainer() with success = false and errorReason = "Container not found" - * Verifying that Terminate() handles such cases gracefully and still returns Core::ERROR_NONE - * Asserting robustness of Terminate() when handling syntactically invalid or unrecognized container IDs - * Releasing the Runtime Manager Interface object and associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateWithInvalidContainerId) { - string appInstanceId("_567gshg&*rt-"); // invalid ID - - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StopContainer(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "Container not found"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_NONE, interface->Terminate(appInstanceId)); - releaseResources(); -} - -/* Test Case for TerminateAlreadyStoppedContainer - * - * Setting up Runtime Manager Plugin and initializing required COM-RPC resources - * Using a valid appInstanceId ("youTube") assumed to be associated with a container - * Simulating the scenario where the container has already been stopped - * Mocking StopContainer() to return success = false and errorReason = "Container already stopped" - * Expecting Terminate() to correctly interpret the failure and return Core::ERROR_GENERAL - * Validating that Runtime Manager handles already-stopped containers gracefully - * Releasing the Runtime Manager Interface object and all associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateAlreadyStoppedContainer) { - string appInstanceId("youTube"); - EXPECT_EQ(true, createResources()); - - // Mock container as already stopped - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, false, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "Container already stopped"; - return Core::ERROR_GENERAL; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Terminate(appInstanceId)); - releaseResources(); -} - -/* Test Case for TerminateWithForceFails - * - * Setting up the Runtime Manager Plugin and initializing necessary COM-RPC resources - * Using a valid appInstanceId ("youTube") to simulate a container instance - * Invoking Kill() method, which attempts to forcefully stop the container - * Mocking StopContainer() with force flag set to true, simulating a system failure - * Returning success = false and errorReason = "System error: Cannot kill process" - * Expecting Kill() to return Core::ERROR_GENERAL to indicate failure - * Verifying that Runtime Manager handles forced termination failures correctly - * Releasing the Runtime Manager Interface and associated test resources - */ -TEST_F(RuntimeManagerTest, TerminateWithForceFails) { - string appInstanceId("youTube"); - EXPECT_EQ(true, createResources()); - - // Mock force-stop failure - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, true, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "System error: Cannot kill process"; - return Core::ERROR_GENERAL; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Kill(appInstanceId)); - releaseResources(); -} - -/* Test Case for KillNonExistentContainer - * - * Initializing the Runtime Manager Plugin and required COM-RPC resources - * Using an invalid appInstanceId ("Invalid") to simulate a non-existent container - * Calling Kill() method, which internally calls StopContainer() with force = true - * Mocking StopContainer() to simulate failure with error reason "Container not found" - * Returning success = false to indicate failure in locating or stopping the container - * Verifying that Kill() returns Core::ERROR_GENERAL for non-existent containers - * Ensuring Runtime Manager gracefully handles forced termination of invalid containers - * Releasing the Runtime Manager Interface and all associated test resources - */ -TEST_F(RuntimeManagerTest, KillNonExistentContainer) { - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StopContainer("com.sky.as.appsInvalid", true, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "Container not found"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->Kill("Invalid")); - releaseResources(); -} - -/* Test Case for KillWithPermissionDenied - * - * Initializing the Runtime Manager Plugin and required COM-RPC resources - * Using a valid appInstanceId ("youTube") to simulate a known container - * Calling Kill() method, which internally calls StopContainer() with force = true - * Mocking StopContainer() to simulate failure due to permission issues - * Returning success = false and errorReason = "Permission denied" from the mock - * Verifying that Kill() method propagates the failure and returns Core::ERROR_GENERAL - * Ensuring Runtime Manager gracefully handles forced termination failures caused by insufficient permissions - * Releasing the Runtime Manager Interface and all associated test resources - */ -TEST_F(RuntimeManagerTest, KillWithPermissionDenied) { - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StopContainer(::testing::_, true, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, bool, bool& success, string& errorReason) { - success = false; - errorReason = "Permission denied"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->Kill("youTube")); - releaseResources(); -} - -/* Test Case for HibernateMethods - * - * Initializing the Runtime Manager Plugin and setting up necessary COM-RPC resources - * Using a valid appInstanceId ("youTube") to simulate an existing container - * Calling Hibernate() method to transition the container into a hibernated state - * Setting up a mock expectation on HibernateContainer() to simulate successful hibernation - * Mock returns success = true with no error, emulating successful state transition - * Asserting that Hibernate() returns Core::ERROR_NONE indicating successful execution - * Ensures Runtime Manager correctly invokes container hibernation logic and handles the response - * Releasing the Runtime Manager Interface object and cleaning up all associated test resources - */ -TEST_F(RuntimeManagerTest, HibernateMethods) -{ - string appInstanceId("youTube"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, HibernateContainer(TEST_APP_CONTAINER_ID, "",::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Hibernate(appInstanceId)); - releaseResources(); -} - -/* Test Case for HibernateFailsWithEmptyAppInstanceId - * - * Setting up the Runtime Manager Plugin and creating necessary COM-RPC resources - * Using an empty string for appInstanceId to simulate invalid or missing input - * Ensuring the Hibernate() method gracefully rejects the invalid appInstanceId - * Setting up mock expectation on HibernateContainer(), though it should ideally not be called - * The method under test should perform input validation and return Core::ERROR_GENERAL - * This test verifies that the Runtime Manager properly handles invalid app identifiers - * Releasing the Runtime Manager Interface object and associated test resources - */ -TEST_F(RuntimeManagerTest, HibernateFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, HibernateContainer(TEST_APP_CONTAINER_ID, "",::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Hibernate(appInstanceId)); - releaseResources(); -} - -/* Test Case for KillMethods - * - * Setting up the Runtime Manager Plugin and initializing required COM-RPC resources - * Simulating a valid container instance with appInstanceId "youTube" - * Setting up mock expectation on StopContainer() with force flag set to true - * Mock simulates successful forced termination of the container - * Calling Kill() method to terminate the appInstance forcibly - * Verifying that Kill() triggers StopContainer() with the correct parameters - * Asserting that Kill() returns Core::ERROR_NONE to indicate success - * Releasing the Runtime Manager Interface object and cleaning up test resources - */ -TEST_F(RuntimeManagerTest, KillMethods) -{ - string appInstanceId("youTube"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, true,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool force, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Kill(appInstanceId)); - releaseResources(); -} - -/* Test Case for KillFailsWithEmptyAppInstanceId - * - * Setting up the Runtime Manager Plugin and initializing COM-RPC test resources - * Providing an empty appInstanceId to simulate invalid input - * Setting mock expectation for StopContainer() with forced termination (though it should not be called) - * Calling Kill() with an empty appInstanceId - * Verifying that Kill() correctly identifies invalid input and returns Core::ERROR_GENERAL - * Releasing the Runtime Manager Interface object and cleaning up test resources - */ -TEST_F(RuntimeManagerTest, KillFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StopContainer(TEST_APP_CONTAINER_ID, true,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool force, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Kill(appInstanceId)); - releaseResources(); -} - -/* Test Case for AnnonateMethods - * - * Setting up the Runtime Manager Plugin and creating necessary COM-RPC resources - * Defining a valid appInstanceId along with key-value annotation data - * Setting up mock expectation on Annotate() to simulate successful container annotation - * Verifying that Annotate() is invoked with the correct container ID and key-value pair - * Asserting that the Annotate() method returns Core::ERROR_NONE upon success - * Cleaning up by releasing the Runtime Manager Interface object and test resources - */ -TEST_F(RuntimeManagerTest, AnnonateMethods) -{ - string appInstanceId("youTube"); - string appKey("youTube_Key"); - string appValue("youTube_Key"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, Annotate(TEST_APP_CONTAINER_ID, appKey,appValue,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string& , const string& , bool& success , string& errorReason ){ - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Annotate(appInstanceId, appKey, appValue)); - releaseResources(); -} - -/* Test Case for AnnotateWithEmptyKeyOrValue - * - * Initializing the Runtime Manager Plugin and creating necessary test resources - * Invoking Annotate() with a valid appInstanceId but an empty key to simulate invalid input - * Verifying that the Annotate() method returns Core::ERROR_GENERAL when key is empty - * Ensuring no actual container annotation is attempted with invalid parameters - * Releasing all Runtime Manager Interface resources after test execution - */ -TEST_F(RuntimeManagerTest, AnnotateWithEmptyKeyOrValue) { - EXPECT_EQ(true, createResources()); - EXPECT_EQ(Core::ERROR_GENERAL, interface->Annotate("youTube", "", "value")); // Empty key - releaseResources(); -} - -/* Test Case for AnnotateNonExistentContainer - * - * Setting up Runtime Manager Plugin and creating required COM-RPC resources - * Simulating an invalid or non-existent container with appInstanceId "Invalid" - * Expecting Annotate() to attempt annotation via the mocked OCI container interface - * Mocking Annotate() call to simulate failure due to "Container not found" - * Verifying that Annotate() returns Core::ERROR_GENERAL when the target container does not exist - * Releasing all Runtime Manager Interface resources after test execution - */ -TEST_F(RuntimeManagerTest, AnnotateNonExistentContainer) { - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, Annotate("com.sky.as.appsInvalid", ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, const string&, bool& success, string& errorReason) { - success = false; - errorReason = "Container not found"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->Annotate("Invalid", "key", "value")); - releaseResources(); -} - -/* Test Case for AnnotateFailsWithEmptyAppInstanceId - * - * Setting up Runtime Manager Plugin and initializing required COM-RPC resources - * Using an empty string as the appInstanceId to simulate invalid input - * Setting mock expectation for Annotate() even though it should not be called due to validation failure - * Calling Annotate() with empty appInstanceId and verifying it fails gracefully - * Asserting that Annotate() returns Core::ERROR_GENERAL due to missing app identifier - * Releasing Runtime Manager Interface resources after the test - */ -TEST_F(RuntimeManagerTest, AnnotateFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - string appKey("youTube_Key"); - string appValue("youTube_Key"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, Annotate(TEST_APP_CONTAINER_ID, appKey,appValue,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string& , const string& , bool& success , string& errorReason ){ - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Annotate(appInstanceId, appKey, appValue)); - releaseResources(); -} - -/* Test Case for GetInfoMethods - * - * Setting up Runtime Manager Plugin and initializing COM-RPC resources - * Using a valid appInstanceId ("youTube") for retrieving container information - * Setting up mock expectation for GetContainerInfo() to return a JSON-formatted string - * Mock returns simulated app stats like RAM usage, CPU load, GPU memory, and uptime - * Calling GetInfo() and asserting it successfully retrieves the expected JSON info - * Verifying that the returned info string exactly matches the mocked expected value - * Releasing Runtime Manager Interface resources after the test - */ -TEST_F(RuntimeManagerTest, GetInfoMethods) -{ - string appInstanceId("youTube"); - string appInfo(""); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, GetContainerInfo(TEST_APP_CONTAINER_ID, ::testing::_,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , string& info , bool& success , string& errorReason ){ - info = expectedAppInfo; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->GetInfo(appInstanceId, appInfo)); - EXPECT_STREQ(appInfo.c_str(), expectedAppInfo.c_str()); - releaseResources(); -} - -/* Test Case for GetInfoForNonExistentContainer - * - * Setting up Runtime Manager Plugin and initializing COM-RPC resources - * Using an invalid appInstanceId ("Invalid") that doesn't map to any container - * Setting up mock expectation on GetContainerInfo() to simulate failure due to missing container - * Mock populates an appropriate error message and sets success to false - * Calling GetInfo() and asserting it returns Core::ERROR_GENERAL - * Verifying that the output string `appInfo` remains empty as no data is available - * Releasing Runtime Manager Interface resources after the test - */ -TEST_F(RuntimeManagerTest, GetInfoForNonExistentContainer) { - string appInfo; - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, GetContainerInfo("com.sky.as.appsInvalid", ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, string& info, bool& success, string& errorReason) { - info = ""; - success = false; - errorReason = "Container not found"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->GetInfo("Invalid", appInfo)); - EXPECT_TRUE(appInfo.empty()); - releaseResources(); -} - -/* Test Case for GetInfoForValidContainerReturnError - * - * Initializing Runtime Manager Plugin and associated COM-RPC resources - * Using an invalid appInstanceId ("Invalid") that maps to a valid container ID format - * Setting up a mock for GetContainerInfo() to simulate a failure due to internal error - * Mock sets `success = true` but returns Core::ERROR_GENERAL to mimic partial failure scenario - * Ensures GetInfo() handles such inconsistent success/error status correctly - * Verifies that the returned `appInfo` string is empty and error code is Core::ERROR_GENERAL - * Releases the test resources after the scenario - */ -TEST_F(RuntimeManagerTest, GetInfoForValidContainerReturnError) { - string appInfo; - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, GetContainerInfo("com.sky.as.appsInvalid", ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, string& info, bool& success, string& errorReason) { - info = ""; - success = true; - errorReason = "No Error"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->GetInfo("Invalid", appInfo)); - EXPECT_TRUE(appInfo.empty()); - releaseResources(); -} - -/* Test Case for GetInfoFailsWithEmptyAppInstanceId - * - * Initializes the Runtime Manager Plugin and required COM-RPC resources - * Provides an empty string as the appInstanceId, which is considered invalid input - * Sets up a mock expectation on GetContainerInfo() with a valid container ID - * Even though the mock simulates a successful container info retrieval, - * the plugin logic is expected to reject the call due to empty appInstanceId - * Verifies that GetInfo() returns Core::ERROR_GENERAL in such cases - * Releases the Runtime Manager Interface resources after validation - */ -TEST_F(RuntimeManagerTest, GetInfoFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - string appInfo(""); - string expectedAppInfo("This Test YouTube"); - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, GetContainerInfo(TEST_APP_CONTAINER_ID, ::testing::_,::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , string& info , bool& success , string& errorReason ){ - info = expectedAppInfo; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->GetInfo(appInstanceId, appInfo)); - releaseResources(); -} - -/* Test Case for RunMethods - * - * Sets up Runtime Manager with valid inputs including environment, ports, and paths - * Mocks StartContainerFromDobbySpec and CreateDisplay for a successful run path - * Verifies that Run() launches the container and initializes display as expected - * Ensures Run() returns Core::ERROR_NONE on success and releases resources - */ -TEST_F(RuntimeManagerTest, RunMethods) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)) - .WillByDefault(::testing::Return(Core::ERROR_NONE)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - releaseResources(); -} - -/* Test Case for RunWithoutCreateDisplay - * - * Simulates successful container start using mocked StartContainerFromDobbySpec - * Forces CreateDisplay() to return Core::ERROR_GENERAL to simulate display creation failure - * Verifies that Run() still proceeds and returns Core::ERROR_NONE despite display issue - * Ensures all resources are cleaned up post execution - */ -TEST_F(RuntimeManagerTest, RunWithoutCreateDisplay) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)) - .WillByDefault(::testing::Return(Core::ERROR_GENERAL)); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - releaseResources(); -} - -/* Test Case for RunCreateFkpsMounts - * - * Sets up FKPS file under /opt/drm and includes it in runtime config JSON array - * Simulates container start and display creation using mocks - * Validates that Run() successfully mounts FKPS file and proceeds with execution - * Ensures proper creation of FKPS content and cleanup after test run - */ -TEST_F(RuntimeManagerTest, RunCreateFkpsMounts) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - std::string fkpsFileName = "test1.fkps"; - std::string fkpsDir = "/opt/drm"; - std::string fkpsFullPath = fkpsDir + "/" + fkpsFileName; - - mkdir(fkpsDir.c_str(), 0755); // Ensure /opt/drm exists - - { - std::ofstream fkpsFile(fkpsFullPath); - ASSERT_TRUE(fkpsFile.is_open()) << "Failed to create FKPS file"; - fkpsFile << "dummy FKPS content"; - } - - runtimeConfig.fkpsFiles = R"(["test1.fkps"])"; // JSON array of FKPS file - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)) - .WillByDefault(::testing::Return(Core::ERROR_NONE)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - releaseResources(); -} - -/* Test Case for RunReadfromAIConfigFile - * - * Creates a mock config.ini with various runtime parameters in /opt/demo - * Validates that RuntimeManager correctly reads and applies AI configuration - * Simulates container start and display creation via mocks - * Ensures Run() completes successfully with loaded config values - * Cleans up config file after test completion - */ -TEST_F(RuntimeManagerTest, RunReadfromAIConfigFile) -{ - const std::string configDir = "/opt/demo"; - const std::string configFilePath = configDir + "/config.ini"; - const std::string appInstanceId = "testAppInstance"; - - if (access(configDir.c_str(), F_OK) != 0) { - int ret = mkdir(configDir.c_str(), 0755); - ASSERT_EQ(ret, 0) << "Failed to create directory: " << configDir << " (errno: " << errno << ")"; - } - - { - std::ofstream configFile(configFilePath); - ASSERT_TRUE(configFile.is_open()) << "Unable to open " << configFilePath << " for writing"; - configFile << "consoleLogCap=1024\n"; - configFile << "cores=15\n"; - configFile << "ramLimit=512\n"; - configFile << "gpuMemoryLimit=128\n"; - configFile << "vpuAccessBlacklist=item1,item2\n"; - configFile << "appsRequiringDBus=app1,app2\n"; - configFile << "mapiPorts=1234,5678\n"; - configFile << "resourceManagerClientEnabled=true\n"; - configFile << "gstreamerRegistryEnabled=true\n"; - configFile << "svpEnabled=true\n"; - configFile << "enableUsbMassStorage=true\n"; - configFile << "ipv6Enabled=true\n"; - configFile << "ionDefaultLimit=2048\n"; - configFile << "dialServerPort=8080\n"; - configFile << "dialServerPathPrefix=\"/prefix\"\n"; - configFile << "dialUsn=\"uuid:1234\"\n"; - configFile << "ionLimits=item1:1000,item2:2000\n"; - configFile << "preloads=lib1,lib2\n"; - configFile << "envVariables=VAR1=1,VAR2=2\n"; - configFile.close(); - } - - std::vector portList = { 1234 }; - std::vector pathsList = { "/tmp" }; - std::vector debugSettingsList = { "INFO" }; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=wst-test"; - runtimeConfig.appPath = "/var/testApp"; - runtimeConfig.runtimePath = "/tmp/testApp"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [](const std::string&, const std::string&, const std::string&, const std::string&, int32_t& descriptor, bool& success, std::string& errorReason) { - descriptor = 99; - success = true; - errorReason = ""; - return Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)).WillByDefault(::testing::Return(Core::ERROR_NONE)); - - LOGINFO("Calling Run"); - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 1000, 1001, - portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - // Optional: Clean up the config file after test - remove(configFilePath.c_str()); - releaseResources(); -} - -/* Test Case for StartContainerFailure - * - * Simulates failure in starting a container due to invalid Dobby spec - * Sets up necessary runtime config and mock environment for container start - * Mocks StartContainerFromDobbySpec() to return failure and error message - * Verifies that Run() returns Core::ERROR_GENERAL on container start failure - */ -TEST_F(RuntimeManagerTest, StartContainerFailure) { - - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ) { - descriptor = -1; - success = false; - errorReason = "Dobby spec invalid"; - return Core::ERROR_GENERAL; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); // Pass valid args - releaseResources(); -} - -/* Test Case for RunWithEmptyContainerId - * - * Validates behavior when Run() is invoked with an empty appInstanceId - * Sets up basic environment variables and runtime configuration - * Passes empty container ID and expects Run() to fail with Core::ERROR_GENERAL - * Ensures interface handles invalid input gracefully and exits early - */ -TEST_F(RuntimeManagerTest, RunWithEmptyContainerId) { - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/valid/path"; - runtimeConfig.runtimePath = "/valid/runtime"; - - EXPECT_EQ(true, createResources()); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Run( - "", "", 10, 10, nullptr, nullptr, nullptr, - runtimeConfig - )); - releaseResources(); -} - -/* Test Case for RunWithDuplicateContainerId - * - * Verifies that Run() fails when attempting to start a container with a duplicate container ID - * Mocks StartContainerFromDobbySpec() to simulate conflict with existing container - * Expects Run() to return Core::ERROR_GENERAL due to ID collision - * Ensures the interface handles duplicate container scenarios gracefully - */ -TEST_F(RuntimeManagerTest, RunWithDuplicateContainerId) { - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ) { - descriptor = -1; - success = false; - errorReason = "Container ID already exists"; - return Core::ERROR_GENERAL; - })); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/valid/path"; - runtimeConfig.runtimePath = "/valid/runtime"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Run( - "youTube", "youTube", 10, 10, nullptr, nullptr, nullptr,runtimeConfig - )); - releaseResources(); -} - -/* Test Case for RunWithTimeout - * - * Simulates a timeout error while invoking StartContainerFromDobbySpec during Run() - * Mocks container start to return failure with "Operation timed out" error - * Verifies Run() handles timeout failure gracefully and returns Core::ERROR_GENERAL - * Confirms the system does not proceed with launch on start timeout - */ -TEST_F(RuntimeManagerTest, RunWithTimeout) { - EXPECT_EQ(true, createResources()); - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success , string& errorReason ) { - descriptor = -1; - success = false; - errorReason = "Operation timed out"; - return Core::ERROR_GENERAL; - })); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/valid/path"; - runtimeConfig.runtimePath = "/valid/runtime"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Run( - "youTube", "youTube", 10, 10, nullptr, nullptr, nullptr,runtimeConfig - )); - releaseResources(); -} - -/* Test Case for WakeMethods - * - * Verifies successful Run, Hibernate, and Wake transitions for a container - * Mocks StartContainerFromDobbySpec, HibernateContainer, and WakeupContainer with success responses - * Ensures Wake() is called after container is successfully hibernated - * Asserts all three operations (Run ? Hibernate ? Wake) complete with Core::ERROR_NONE - */ -TEST_F(RuntimeManagerTest, WakeMethods) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - EXPECT_CALL(*mociContainerMock, HibernateContainer(TEST_APP_CONTAINER_ID, "",::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Hibernate(appInstanceId)); - - EXPECT_CALL(*mociContainerMock, WakeupContainer(TEST_APP_CONTAINER_ID, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Wake(appInstanceId, WPEFramework::Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING)); - - releaseResources(); -} - -/* Test Case for WakeOnRunningNonHibernateContainer - * - * Ensures Wake() fails if invoked without prior Hibernate() - * Mocks StartContainerFromDobbySpec with a successful container start - * Does not call HibernateContainer before Wake() - * Expects Wake() to return Core::ERROR_GENERAL indicating invalid state transition - */ -TEST_F(RuntimeManagerTest, WakeOnRunningNonHibernateContainer) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Wake(appInstanceId, WPEFramework::Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING)); - - releaseResources(); -} - -/* Test Case for WakeWithGeneralError - * - * Validates Wake() failure when WakeupContainer returns an error - * Simulates successful Run() and Hibernate() calls for the container - * Mocks WakeupContainer to return Core::ERROR_GENERAL with failure status - * Expects Wake() to return Core::ERROR_GENERAL due to internal wakeup failure - */ -TEST_F(RuntimeManagerTest, WakeWithGeneralError) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - EXPECT_CALL(*mociContainerMock, HibernateContainer(TEST_APP_CONTAINER_ID, "",::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, bool& success, string& errorReason) { - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->Hibernate(appInstanceId)); - - EXPECT_CALL(*mociContainerMock, WakeupContainer(TEST_APP_CONTAINER_ID, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string&, bool& success, string& errorReason) { - success = false; - errorReason = "Genral Error"; - return WPEFramework::Core::ERROR_GENERAL; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Wake(appInstanceId, WPEFramework::Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING)); - - releaseResources(); -} - -/* Test Case for WakeOnNonRunningContainer - * - * Verifies Wake() behavior when called on a non-running container - * Does not simulate prior Run() or Hibernate() actions - * Expects Wake() to fail due to missing container context - * Ensures Wake() returns Core::ERROR_GENERAL - */ -TEST_F(RuntimeManagerTest, WakeOnNonRunningContainer) -{ - string appInstanceId("youTube"); - EXPECT_EQ(true, createResources()); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Wake(appInstanceId, WPEFramework::Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING)); - - releaseResources(); -} - -/* Test Case for WakeFailsWithEmptyAppInstanceId - * - * Validates Wake() behavior when provided an empty appInstanceId - * No container is associated with the empty ID - * Expects Wake() to fail gracefully - * Ensures it returns Core::ERROR_GENERAL - */ -TEST_F(RuntimeManagerTest, WakeFailsWithEmptyAppInstanceId) -{ - string appInstanceId(""); - - EXPECT_EQ(true, createResources()); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Wake(appInstanceId, WPEFramework::Exchange::IRuntimeManager::RUNTIME_STATE_RUNNING)); - - releaseResources(); -} - -/* Test Case for SuspendResumeMethods - * - * Verifies the suspend and resume lifecycle operations on a running container - * Mocks PauseContainer and ResumeContainer with success responses - * Ensures both Suspend() and Resume() return Core::ERROR_NONE - * Validates end-to-end control flow of container pause/resume - */ -TEST_F(RuntimeManagerTest, SuspendResumeMethods) -{ - string appInstanceId("youTube"); - string expectedAppInfo = R"({"ramUsage": "150MB","cpuUsage": "20%","gpuMemory": "32MB","uptime": "45s"})"; - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - WPEFramework::Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AnyNumber()) - .WillOnce(::testing::Invoke( - [&](const string& , const string&, const string&, const string&,int32_t& descriptor, bool& success, string& errorReason ){ - descriptor = 100; - success = true; - errorReason = "No Error"; - return WPEFramework::Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)) - .WillByDefault(::testing::Return(Core::ERROR_NONE)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - EXPECT_CALL(*mociContainerMock, PauseContainer(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const std::string&, bool& success, std::string& reason) { - success = true; - reason = "No Error"; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, interface->Suspend(appInstanceId)); - - EXPECT_CALL(*mociContainerMock, ResumeContainer(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const std::string& containerId, bool& success, std::string& reason) { - success = true; - reason = "No Error"; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, interface->Resume(appInstanceId)); - releaseResources(); -} - -/* Test: SuspendFailsWithEmptyAppInstanceId - * - * Purpose: Verify Suspend() fails when appInstanceId is empty. - * Expectation: PauseContainer should not be called. - * Result: Suspend() should return Core::ERROR_GENERAL. - * Validates input checking for Suspend(). - */ -TEST_F(RuntimeManagerTest, SuspendFailsWithEmptyAppInstanceId) -{ - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, PauseContainer(::testing::_, ::testing::_, ::testing::_)) - .Times(0); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Suspend("")); - - releaseResources(); -} - -/* Test Case for SuspendFailsWithEmptyAppInstanceId - * - * Ensures Suspend() fails gracefully when appInstanceId is empty - * Verifies that PauseContainer is not invoked - * Expects Core::ERROR_GENERAL as the return value - * Validates input sanity checks in Suspend() - */ -TEST_F(RuntimeManagerTest, ResumeFailsWithEmptyAppInstanceId) -{ - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, ResumeContainer(::testing::_, ::testing::_, ::testing::_)) - .Times(0); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Resume("")); - - releaseResources(); -} - -/* Test: SuspendFailsWithPauseContainerError - * - * Purpose: Validate behavior when PauseContainer fails during Suspend(). - * Setup: Mocks StartContainerFromDobbySpec to succeed and PauseContainer to fail. - * Expectation: Suspend() should return Core::ERROR_GENERAL on failure. - * Confirms error handling path in Suspend(). - */ -TEST_F(RuntimeManagerTest, SuspendFailsWithPauseContainerError) -{ - string appInstanceId("youTube"); - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, const string&, const string&, int32_t& descriptor, bool& success, string& errorReason) { - descriptor = 100; - success = true; - errorReason = "No Error"; - return Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)).WillByDefault(::testing::Return(Core::ERROR_NONE)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - EXPECT_CALL(*mociContainerMock, PauseContainer(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const std::string&, bool& success, std::string& reason) { - success = false; - reason = "Mocked failure"; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Suspend(appInstanceId)); - - releaseResources(); -} - -/* Test: ResumeFailsResumePauseContainerError - * - * Purpose: Verify that Resume() handles failure in ResumeContainer properly. - * Setup: - * - Mocks StartContainerFromDobbySpec to succeed. - * - Mocks PauseContainer to succeed. - * - Mocks ResumeContainer to return Core::ERROR_GENERAL and fail. - * Expectation: Resume() returns Core::ERROR_GENERAL indicating failure. - * Validates error path in Resume(). - */ -TEST_F(RuntimeManagerTest, ResumeFailsResumePauseContainerError) -{ - string appInstanceId("youTube"); - std::vector portList = {10, 20}; - std::vector pathsList = {"/tmp", "/opt"}; - std::vector debugSettingsList = {"MIL", "INFO"}; - - auto portsIterator = Core::Service>::Create(portList); - auto pathsListIterator = Core::Service>::Create(pathsList); - auto debugSettingsIterator = Core::Service>::Create(debugSettingsList); - - Exchange::RuntimeConfig runtimeConfig; - runtimeConfig.envVariables = "XDG_RUNTIME_DIR=/tmp;WAYLAND_DISPLAY=main"; - runtimeConfig.appPath = "/var/runTimeManager"; - runtimeConfig.runtimePath = "/tmp/runTimeManager"; - runtimeConfig.systemMemoryLimit = 512; - runtimeConfig.command ="SkyBrowserLauncher"; - - EXPECT_EQ(true, createResources()); - - EXPECT_CALL(*mociContainerMock, StartContainerFromDobbySpec(TEST_APP_CONTAINER_ID, ::testing::_, "", "/run/user/1001/wst-youTube", ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](const string&, const string&, const string&, const string&, int32_t& descriptor, bool& success, string& errorReason) { - descriptor = 100; - success = true; - errorReason = "No Error"; - return Core::ERROR_NONE; - })); - - ON_CALL(*mWindowManagerMock, CreateDisplay(::testing::_)).WillByDefault(::testing::Return(Core::ERROR_NONE)); - - EXPECT_EQ(Core::ERROR_NONE, interface->Run(appInstanceId, appInstanceId, 10, 10, portsIterator, pathsListIterator, debugSettingsIterator, runtimeConfig)); - - EXPECT_CALL(*mociContainerMock, PauseContainer(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const std::string&, bool& success, std::string& reason) { - success = true; - reason = "No Error"; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, interface->Suspend(appInstanceId)); - - EXPECT_CALL(*mociContainerMock, ResumeContainer(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const std::string& containerId, bool& success, std::string& reason) { - success = false; - reason = "Mocked Failure"; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->Resume(appInstanceId)); - - releaseResources(); -} - -/* Test: OCIContainerEvents - * - * Purpose: Verify that the RuntimeManager correctly handles all OCI container lifecycle events. - * Setup: - * - Creates dummy event data and container name. - * - Calls event handlers: onOCIContainerStartedEvent, onOCIContainerStoppedEvent, - * onOCIContainerFailureEvent, and onOCIContainerStateChangedEvent. - * Expectation: - * - No assertion failures or crashes. - * - Ensures that the event-handling methods are callable and don't throw or misbehave under basic conditions. - */ -TEST_F(RuntimeManagerTest, OCIContainerEvents) -{ - ASSERT_TRUE(createResources()); - - JsonObject dummyData; - std::string dummyName = "DummyApp"; - - mRuntimeManagerImpl->onOCIContainerStartedEvent(dummyName, dummyData); - mRuntimeManagerImpl->onOCIContainerStoppedEvent(dummyName, dummyData); - mRuntimeManagerImpl->onOCIContainerFailureEvent(dummyName, dummyData); - mRuntimeManagerImpl->onOCIContainerStateChangedEvent(dummyName, dummyData); - - releaseResources(); -} - -/* Test: MountMethods - * - * Purpose: Ensure the stubbed Mount() method can be called successfully. - * Note: This is a stubbed method, added purely for code coverage. - */ -TEST_F(RuntimeManagerTest, MountMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, interface->Mount()); -} - -/* Test: UnmountMethods - * - * Purpose: Ensure the stubbed Unmount() method can be called successfully. - * Note: This is a stubbed method, added purely for code coverage. - */ -TEST_F(RuntimeManagerTest, UnmountMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, interface->Unmount()); -} - diff --git a/Tests/L1Tests/tests/test_StorageManager.cpp b/Tests/L1Tests/tests/test_StorageManager.cpp deleted file mode 100755 index a4cea84..0000000 --- a/Tests/L1Tests/tests/test_StorageManager.cpp +++ /dev/null @@ -1,980 +0,0 @@ -#include -#include -#include -#include -#include "StorageManager.h" -#include "StorageManagerImplementation.h" -#include "ServiceMock.h" -#include "Store2Mock.h" -#include "WrapsMock.h" -#include "ThunderPortability.h" -#include "COMLinkMock.h" -#include "RequestHandler.h" - -extern "C" DIR* __real_opendir(const char* pathname); - -using ::testing::NiceMock; -using ::testing::Return; -using namespace WPEFramework; - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -class StorageManagerTest : public ::testing::Test { - protected: - //JSONRPC - Core::ProxyType plugin; // create a proxy object - Core::JSONRPC::Handler& handler; - Core::JSONRPC::Context connection; // create a JSONRPC context - string response; // create a string to hold the response - Exchange::IConfiguration* storageManagerConfigure; // create a pointer to IConfiguration - //comrpc - Exchange::IStorageManager* interface; // create a pointer to IStorageManager - NiceMock service; // an instance of mock service object - Core::ProxyType StorageManagerImplementation; // declare an proxy object - ServiceMock *p_serviceMock = nullptr; - WrapsImplMock *p_wrapsImplMock = nullptr; - - Store2Mock* mStore2Mock = nullptr; - - StorageManagerTest(): - plugin(Core::ProxyType::Create()), - handler(*plugin), - connection(0,1,"") - { - StorageManagerImplementation = Core::ProxyType::Create(); - mStore2Mock = new NiceMock; - - p_wrapsImplMock = new NiceMock ; - Wraps::setImpl(p_wrapsImplMock); - static struct dirent mockDirent; - std::memset(&mockDirent, 0, sizeof(mockDirent)); - std::strncpy(mockDirent.d_name, "mockApp", sizeof(mockDirent.d_name) - 1); - mockDirent.d_type = DT_DIR; - ON_CALL(*mStore2Mock, GetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](Exchange::IStore2::ScopeType scope, const std::string& appId, const std::string& key, std::string& value, uint32_t& ttl) -> uint32_t { - if (key == "quotaSize") { - value = "1024"; // Simulate a valid numeric quota - } else { - value = "mockValue"; // Default value for other keys - } - - ttl = 0; - return Core::ERROR_NONE; - })); - - ON_CALL(*p_wrapsImplMock, opendir(::testing::_)) - .WillByDefault(::testing::Invoke([](const char* pathname) { - // Simulate success - return __real_opendir(pathname); - })); - ON_CALL(*p_wrapsImplMock, readdir(::testing::_)) - .WillByDefault([](DIR* dirp) -> struct dirent* { - static int call_count = 0; - static struct dirent entry; - if (call_count == 0) { - std::strncpy(entry.d_name, "mockApp", sizeof(entry.d_name) - 1); - entry.d_type = DT_DIR; - call_count++; - return &entry; - } else if (call_count == 1) { - std::strncpy(entry.d_name, "testApp", sizeof(entry.d_name) - 1); - entry.d_type = DT_DIR; - call_count++; - return &entry; - } else { - call_count = 0; // Reset for next traversal - return nullptr; - } - }); - - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, struct stat* info) { - // Simulate success - return 0; - }); - - ON_CALL(*p_wrapsImplMock, closedir(::testing::_)) - .WillByDefault([](DIR* dirp) { - // Simulate success - return 0; - }); - - EXPECT_CALL(service, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](const uint32_t, const std::string& name) -> void* { - if (name == "org.rdk.PersistentStore") { - return reinterpret_cast(mStore2Mock); - } - return nullptr; - })); - - interface = static_cast( - StorageManagerImplementation->QueryInterface(Exchange::IStorageManager::ID)); - - storageManagerConfigure = static_cast( - StorageManagerImplementation->QueryInterface(Exchange::IConfiguration::ID)); - StorageManagerImplementation->Configure(&service); - plugin->Initialize(&service); - - } - virtual ~StorageManagerTest() override { - plugin->Deinitialize(&service); - storageManagerConfigure->Release(); - Wraps::setImpl(nullptr); - if (p_wrapsImplMock != nullptr) - { - delete p_wrapsImplMock; - p_wrapsImplMock = nullptr; - } - if (mStore2Mock != nullptr) - { - delete mStore2Mock; - mStore2Mock = nullptr; - } - - } - virtual void SetUp() - { - ASSERT_TRUE(interface != nullptr); - } - - virtual void TearDown() - { - ASSERT_TRUE(interface != nullptr); - } - }; - - -/* - Test for CreateStorage with empty appId - This test checks the failure case when an empty appId is provided. - It expects the CreateStorage method to return an error code and set the error reason accordingly. - The test verifies that the error reason matches the expected message "appId cannot be empty". - It also logs the error reason for debugging purposes. -*/ -TEST_F(StorageManagerTest, CreateStorage_Failure){ - std::string appId = ""; - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - EXPECT_EQ(Core::ERROR_GENERAL, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("appId cannot be empty", errorReason.c_str()); - TEST_LOG("CreateStorage_Failure errorReason = %s",errorReason.c_str()); - -} - -/* - CreateStorage_Success test checks the failure of creation of storage for a given appId due to insufficient storage space. - Creates a mock environment where the necessary functions like mkdir, access, nftw, are set up to simulate a successful resutls. - Creates a mock environment where the statvfs function is set up to simulate a unsuccessful result with insufficient storage space. - It verifies that the CreateStorage method returns a failure code and errorReason that Insufficient storage space. - The test also logs the success message for debugging purposes. -*/ -TEST_F(StorageManagerTest, CreateStorageSizeExceeded_Failure){ - std::string appId = "testApp"; - uint32_t size = 1000000; - std::string path = " "; - std::string errorReason = ""; - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - EXPECT_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate failure - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 0; // Free blocks - buf->f_bavail = 0; // Available blocks - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - return Core::ERROR_NONE; - })); - EXPECT_EQ(Core::ERROR_GENERAL, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("Insufficient storage space", errorReason.c_str()); - TEST_LOG("CreateStorageSizeExceeded_Failure errorReason = %s",errorReason.c_str()); -} - -/* - CreateStorage_Success test checks the failure of creation of storage for a given appId due to mkdir failure. - Creates a mock environment where the necessary functions like access, nftw, are set up to simulate a successful resutls. - Creates a mock environment where the mkdir function is set up to simulate a failure with ENOTDIR error. - It verifies that the CreateStorage method returns a failure code and errorReason that Failed to create base storage directory: /opt/persistent/storageManager. - The test also logs the message for debugging purposes. -*/ -TEST_F(StorageManagerTest, CreateStoragemkdirFail_Failure){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillOnce([](const char* path, mode_t mode) { - errno = ENOTDIR; // error that should trigger failure - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("Failed to create base storage directory: /opt/persistent/storageManager", errorReason.c_str()); - TEST_LOG("CreateStoragemkdirFail_Failure errorReason = %s",errorReason.c_str()); - -} - -/* - CreateStorage_PathDoesNotExists_Success test checks the successful creation of storage for a given appId when the path does not exist. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and stat are set up to simulate a successful resutls. - It verifies that the CreateStorage method returns a success code and the errorReason is empty. - The test also logs the success message for debugging purposes. -*/ -TEST_F(StorageManagerTest, CreateStorage_PathDoesNotExists_Success){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - errno = EEXIST; // Directory already exists - return -1; - }); - - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* pathname, int mode) { - // Simulate file exists - return 0; - }); - - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 500000; // Free blocks - buf->f_bavail = 500000; // Available blocks - return 0; - }); - - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, struct stat* info) { - // Simulate success - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("", errorReason.c_str()); - -} - -/* - CreateStorage_Success test checks the successful creation of storage for a given appId. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and stat are set up to simulate a successful resutls. - It verifies that the CreateStorage method returns a success code and the errorReason is empty. - The test also logs the success message for debugging purposes. -*/ -TEST_F(StorageManagerTest, CreateStorage_Success){ - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 500000; // Free blocks - buf->f_bavail = 500000; // Available blocks - return 0; - }); - - ON_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, struct stat* info) { - // Simulate success - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("", errorReason.c_str()); -} - -/* - GetStorage_Failure test checks the failure of getting storage information for a blank appId. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and chown are set up to simulate a successful resutls. - It verifies that the GetStorage method returns a failure code when the appId is empty. -*/ -TEST_F(StorageManagerTest, GetStorage_Failure){ - - std::string appId = ""; - uint32_t userId = 100; - uint32_t groupId = 101; - std::string path = ""; - uint32_t size = 0; - uint32_t used = 0; - - EXPECT_EQ(Core::ERROR_GENERAL, interface->GetStorage(appId, userId, groupId, path, size, used)); -} -/* - GetStorage_chownFailure test checks the failure of getting storage information when the chown operation fails. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, chown are set up to simulate a successful resutls. - chown is set up to simulate a faiure result. - It verifies that the GetStorage method returns a failure code when the chown operation fails. -*/ -TEST_F(StorageManagerTest, GetStorage_chownFailure){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string errorReason = ""; - uint32_t userId = 100; - uint32_t groupId = 101; - std::string path = ""; - uint32_t used = 0; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, chown(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, uid_t owner, gid_t group) { - // Simulate Failure - return -1; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - ON_CALL(*mStore2Mock, GetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](Exchange::IStore2::ScopeType scope, const std::string& appId, const std::string& key, std::string& value, uint32_t& ttl) -> uint32_t { - if (key == "quotaSize") { - value = "1024"; // Simulate a valid numeric quota - } else { - value = "mockValue"; // Default value for other keys - } - ttl = 0; - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_EQ(Core::ERROR_GENERAL, interface->GetStorage(appId, userId, groupId, path, size, used)); -} - -/* - GetStorage_Success test checks the successful retrieval of storage information for a given appId. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and chown are set up to simulate a successful resutls. - It verifies that the GetStorage method returns a success code and the size and used values are set correctly. - The test also checks that the path is set to the expected value. -*/ -TEST_F(StorageManagerTest, GetStorage_Success){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string errorReason = ""; - uint32_t userId = 100; - uint32_t groupId = 101; - std::string path = ""; - uint32_t used = 0; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, chown(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, uid_t owner, gid_t group) { - // Simulate success - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - ON_CALL(*mStore2Mock, GetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](Exchange::IStore2::ScopeType scope, const std::string& appId, const std::string& key, std::string& value, uint32_t& ttl) -> uint32_t { - if (key == "quotaSize") { - value = "1024"; // Simulate a valid numeric quota - } else { - value = "mockValue"; // Default value for other keys - } - ttl = 0; - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, interface->GetStorage(appId, userId, groupId, path, size, used)); - EXPECT_EQ(1024, size); - EXPECT_EQ(0, used); - EXPECT_EQ(path, "/opt/persistent/storageManager/testApp"); -} - -/* - DeleteStorage_Failure test checks the failure of deleting storage for a blank appId. - It verifies that the DeleteStorage method returns a failure code when the appId is empty and sets the errorReason accordingly. - The test also logs the error reason for debugging purposes. -*/ -TEST_F(StorageManagerTest, DeleteStorage_Failure){ - std::string appId = ""; - std::string errorReason = ""; - - EXPECT_EQ(Core::ERROR_GENERAL, interface->DeleteStorage(appId, errorReason)); - EXPECT_STREQ("AppId is empty", errorReason.c_str()); - TEST_LOG("DeleteStorage_Failure errorReason = %s",errorReason.c_str()); -} - -/* - DeleteStorage_rmdirFilure test checks the failure of deleting storage for a given appId when the rmdir function fails. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, are rmdir are set up to simulate a successful results. - rmdir is set up to simulate a failure result. - It verifies that the DeleteStorage method returns a failure code and errorReason that Error deleting the empty App Folder: File exists. -*/ -TEST_F(StorageManagerTest, DeleteStorage_rmdirFilure){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string errorReason = ""; - std::string path = ""; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, rmdir(::testing::_)) - .WillRepeatedly([](const char* pathname) { - // Simulate failure - return -1; - }); - - ON_CALL(*mStore2Mock, DeleteKey(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](Exchange::IStore2::ScopeType scope, const std::string& appId, const std::string& key) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_EQ(Core::ERROR_GENERAL, interface->DeleteStorage(appId, errorReason)); - EXPECT_STREQ("Error deleting the empty App Folder: File exists", errorReason.c_str()); -} - -/* - DeleteStorage_Success test checks the successful deletion of storage for a given appId. - Creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and rmdir are set up to simulate a successful resutls. - It verifies that the DeleteStorage method returns a success code and the errorReason is empty. -*/ -TEST_F(StorageManagerTest, DeleteStorage_Success){ - - std::string appId = "testApp"; - uint32_t size = 1024; - std::string errorReason = ""; - std::string path = ""; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, rmdir(::testing::_)) - .WillRepeatedly([](const char* pathname) { - // Simulate success - return 0; - }); - - ON_CALL(*mStore2Mock, DeleteKey(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](Exchange::IStore2::ScopeType scope, const std::string& appId, const std::string& key) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage(appId, size, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, interface->DeleteStorage(appId, errorReason)); - EXPECT_STREQ("", errorReason.c_str()); -} - - -/* - test_clear_failure_json checks the failure of the clear method when an empty appId is provided. - It verifies that the clear method returns a failure code and sets the errorReason accordingly. - The test also logs the error reason for debugging purposes. -*/ -TEST_F(StorageManagerTest, test_clear_failure_json){ - std::string appId = ""; - std::string errorReason = ""; - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("clear"), _T("{\"appId\":\"\"}"), response)); -} - -/* - test_clear_nftwFailure_json checks the failure of the clear method when the nftw function fails. - It creates a mock environment where the necessary functions like mkdir, access, statvfs, and SetValue are set up to simulate a successful result. - nftw is set up to simulate a failure. - The nftw function is set up to simulate a failure. - It verifies that the clear method returns a failure code and sets the errorReason accordingly. -*/ -TEST_F(StorageManagerTest, test_clear_nftwFailure_json){ - - std::string path = ""; - std::string errorReason = ""; - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate failure - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testApp", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("clear"), _T("{\"appId\":\"testApp\"}"), response)); -} - -/* - test_clear_success_json checks the successful execution of the clear method for a given appId. - It creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and SetValue are set up to simulate a successful result. - It creates a storage for the appId "testApp" with a size of 1024 bytes. - The test then invokes the clear method with the appId "testApp" and expects a success code. - The response is expected to be empty, indicating that the storage has been cleared successfully -*/ -TEST_F(StorageManagerTest, test_clear_success_json){ - - std::string path = ""; - std::string errorReason = ""; - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testApp", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("clear"), _T("{\"appId\":\"testApp\"}"), response)); -} - -/* - test_clearall_failure_json checks the failure of the clearAll method when an error occurs during the clearing process. - It creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and SetValue are set up to simulate a successful result. - It creates storage for two appIds: "testApp" and "testexempt". - The test then invokes the clearAll method with a JSON string containing exemptionAppIds. - It expects the clearAll method to return a failure code and sets the errorReason accordingly. - The test also logs the error reason for debugging purposes. -*/ -TEST_F(StorageManagerTest, test_clearall_failure_json){ - - std::string path = ""; - std::string errorReason = ""; - std::string wrappedJson = "{\"exemptionAppIds\": \"[\\\"testexempt\\\"]\"}"; - static int callCount = 0; - - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - EXPECT_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }) - .WillOnce([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }) - .WillOnce([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }) - .WillOnce([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - EXPECT_CALL(*p_wrapsImplMock, opendir(::testing::_)) - .WillOnce(::testing::Invoke([](const char* pathname) { - // Simulate success - return (__real_opendir(pathname)); - - })); - - ON_CALL(*p_wrapsImplMock, readdir(::testing::_)) - .WillByDefault([](DIR* dirp) -> struct dirent* { - static struct dirent entry; - switch (callCount++) { - case 0: - std::strcpy(entry.d_name, "testApp"); - entry.d_type = DT_DIR; - return &entry; - case 1: - std::strcpy(entry.d_name, "testexempt"); - entry.d_type = DT_DIR; - return &entry; - default: - return nullptr; - } - }); - ON_CALL(*p_wrapsImplMock, closedir(::testing::_)) - .WillByDefault([](DIR* dirp) { - // Simulate success - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testApp", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testexempt", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("clearAll"), wrappedJson, response)); -} - -/* - test_clearall_without_exemption_json checks the successful execution of the clearAll method without any exemption appIds. - It verifies that the clearAll method returns a success code and the response is empty ensuring all storage is cleared. -*/ -TEST_F(StorageManagerTest, test_clearall_without_exemption_json){ - std::string exemptionAppIds = ""; - std::string errorReason = ""; - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("clearAll"), _T("{}"), response)); -} - -/* - test_clearall_success_json checks the successful execution of the clearAll method with exemption appIds. - It creates a mock environment where the necessary functions like mkdir, access, nftw, statvfs, and SetValue are set up to simulate a successful result. - It creates storage for two appIds: "testApp" and "testexempt". - The test then invokes the clearAll method with a JSON string containing exemptionAppIds. - It expects the clearAll method to return a success code and the response is empty indicating that the storage has been cleared successfully except for the exempted appId. -*/ -TEST_F(StorageManagerTest, test_clearall_success_json){ - std::string path = ""; - std::string errorReason = ""; - std::string wrappedJson = "{\"exemptionAppIds\": \"{\\\"exemptionAppIds\\\": [\\\"testexempt\\\"]}\"}"; - static int callCount = 0; - // mock the mkdir function to always return success - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - ON_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillByDefault([](const char* path, int mode) { - // Simulate file exists - return 0; - }); - ON_CALL(*p_wrapsImplMock, nftw(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](const char* dirpath, int (*fn)(const char*, const struct stat*, int, struct FTW*), int nopenfd, int flags) { - // Simulate success - return 0; - }); - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - buf->f_bsize = 4096; // Block size - buf->f_frsize = 4096; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 50000; // Free blocks - buf->f_bavail = 50000; // Available blocks - return 0; - }); - ON_CALL(*mStore2Mock, SetValue(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke([](Exchange::IStore2::ScopeType scope, - const std::string& appId, - const std::string& key, - const std::string& value, - const uint32_t ttl) -> uint32_t { - // Simulate success - return Core::ERROR_NONE; - })); - - ON_CALL(*p_wrapsImplMock, opendir(::testing::_)) - .WillByDefault(::testing::Invoke([](const char* pathname) { - // Simulate success - return (__real_opendir(pathname)); - - })); - - ON_CALL(*p_wrapsImplMock, readdir(::testing::_)) - .WillByDefault([](DIR* dirp) -> struct dirent* { - static struct dirent entry; - switch (callCount++) { - case 0: - std::strcpy(entry.d_name, "testApp"); - entry.d_type = DT_DIR; - return &entry; - case 1: - std::strcpy(entry.d_name, "testexempt"); - entry.d_type = DT_DIR; - return &entry; - default: - return nullptr; - } - }); - - ON_CALL(*p_wrapsImplMock, closedir(::testing::_)) - .WillByDefault([](DIR* dirp) { - // Simulate success - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testApp", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, interface->CreateStorage("testexempt", 1024, path, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("clearAll"), wrappedJson, response)); -} - diff --git a/Tests/L1Tests/tests/test_Telemetry.cpp b/Tests/L1Tests/tests/test_Telemetry.cpp deleted file mode 100644 index 9c46072..0000000 --- a/Tests/L1Tests/tests/test_Telemetry.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "COMLinkMock.h" - -#include "Telemetry.h" -#include "TelemetryImplementation.h" -#include "TelemetryMock.h" -#include "WorkerPoolImplementation.h" -#include "FactoriesImplementation.h" -#include "RfcApiMock.h" -#include "ServiceMock.h" -#include "RBusMock.h" -#include "IarmBusMock.h" -#include "PowerManagerMock.h" -#include "WrapsMock.h" -#include "ThunderPortability.h" - -namespace { -const string profileFN = _T("/tmp/DefaultProfile.json"); -const string t2PpersistentFolder = _T("/tmp/.t2reportprofiles/"); -const uint8_t profileContent[] = "{\"profile\":\"default\"}"; -} - -using namespace WPEFramework; -using ::testing::NiceMock; - -class TelemetryTest : public ::testing::Test { -protected: - NiceMock service; - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - DECL_CORE_JSONRPC_CONX connection; - NiceMock comLinkMock; - Core::ProxyType workerPool; - Core::ProxyType TelemetryImpl; - Exchange::ITelemetry::INotification *TelemetryNotification = nullptr; - string response; - FactoriesImplementation factoriesImplementation; - PLUGINHOST_DISPATCHER *dispatcher; - Core::JSONRPC::Message message; - ServiceMock *p_serviceMock = nullptr; - WrapsImplMock* p_wrapsImplMock = nullptr; - TelemetryApiImplMock* p_telemetryApiImplMock = nullptr; - RfcApiImplMock* p_rfcApiImplMock = nullptr ; - RBusApiImplMock *p_rBusApiImplMock = nullptr; - - TelemetryTest() - : plugin(Core::ProxyType::Create()) - , handler(*plugin) - , INIT_CONX(1, 0) - , workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)) - { - -#ifdef USE_THUNDER_R4 - Core::Directory(t2PpersistentFolder.c_str()).Destroy(); -#else - Core::Directory(t2PpersistentFolder.c_str()).Destroy(true); -#endif /*USE_THUNDER_R4 */ - - p_serviceMock = new NiceMock ; - - p_telemetryApiImplMock = new NiceMock ; - TelemetryApi::setImpl(p_telemetryApiImplMock); - - p_wrapsImplMock = new NiceMock; - Wraps::setImpl(p_wrapsImplMock); - - p_rfcApiImplMock = new NiceMock ; - RfcApi::setImpl(p_rfcApiImplMock); - - - PluginHost::IFactories::Assign(&factoriesImplementation); - - dispatcher = static_cast( - plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); - dispatcher->Activate(&service); - - p_rBusApiImplMock = new NiceMock ; - RBusApi::setImpl(p_rBusApiImplMock); - - ON_CALL(*p_telemetryApiImplMock, Register(::testing::_)) - .WillByDefault(::testing::Invoke( - [&](Exchange::ITelemetry::INotification* notification) { - TelemetryNotification = notification; - return Core::ERROR_NONE; - ; - })); - - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const RPC::Object& object, const uint32_t waitTime, uint32_t& connectionId) { - TelemetryImpl = Core::ProxyType::Create(); - return &TelemetryImpl; - })); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - - plugin->Initialize(&service); - } - - virtual ~TelemetryTest() override - { - - plugin->Deinitialize(&service); - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - - if (p_serviceMock != nullptr) - { - delete p_serviceMock; - p_serviceMock = nullptr; - } - - TelemetryApi::setImpl(nullptr); - if (p_telemetryApiImplMock != nullptr) { - delete p_telemetryApiImplMock; - p_telemetryApiImplMock = nullptr; - } - - Wraps::setImpl(nullptr); - if (p_wrapsImplMock != nullptr) { - delete p_wrapsImplMock; - p_wrapsImplMock = nullptr; - } - - RfcApi::setImpl(nullptr); - if (p_rfcApiImplMock != nullptr) - { - delete p_rfcApiImplMock; - p_rfcApiImplMock = nullptr; - } - - RBusApi::setImpl(nullptr); - if (p_rBusApiImplMock != nullptr) - { - delete p_rBusApiImplMock; - p_rBusApiImplMock = nullptr; - } - - dispatcher->Deactivate(); - dispatcher->Release(); - - PluginHost::IFactories::Assign(nullptr); - } -}; - -TEST_F(TelemetryTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("setReportProfileStatus"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("logApplicationEvent"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("uploadReport"))); -} - -TEST_F(TelemetryTest, InitializeDefaultProfile) -{ - ON_CALL(service, ConfigLine()) - .WillByDefault( - ::testing::Return("{" - "\"t2PersistentFolder\":\"/tmp/.t2reportprofiles/\"," - "\"defaultProfilesFile\":\"/tmp/DefaultProfile.json\"" - "}")); - ON_CALL(*p_rfcApiImplMock, setRFCParameter(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - EXPECT_EQ(string(pcCallerID), _T("Telemetry")); - EXPECT_EQ(string(pcParameterName), _T("Device.X_RDKCENTRAL-COM_T2.ReportProfiles")); - EXPECT_EQ(string(pcParameterValue), _T("{\\\"profile\\\":\\\"default\\\"}")); - EXPECT_EQ(eDataType, WDMP_STRING); - - return WDMP_SUCCESS; - })); - { - Core::Directory(t2PpersistentFolder.c_str()).CreatePath(); - Core::File file(profileFN); - file.Create(); - file.Write(profileContent, sizeof(profileContent)); - } - -} - -TEST_F(TelemetryTest, InitializeDefaultProfileRFCFailure) -{ - ON_CALL(service, ConfigLine()) - .WillByDefault( - ::testing::Return("{" - "\"t2PersistentFolder\":\"/tmp/.t2reportprofiles/\"," - "\"defaultProfilesFile\":\"/tmp/DefaultProfile.json\"" - "}")); - - ON_CALL(*p_rfcApiImplMock, setRFCParameter(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - return WDMP_FAILURE; - })); - - { - Core::Directory(t2PpersistentFolder.c_str()).CreatePath(); - Core::File file(profileFN); - file.Create(); - file.Write(profileContent, sizeof(profileContent)); - } -} - -TEST_F(TelemetryTest, InitializeZeroSizeDefaultProfile) -{ - ON_CALL(service, ConfigLine()) - .WillByDefault( - ::testing::Return("{" - "\"t2PersistentFolder\":\"/tmp/.t2reportprofiles/\"," - "\"defaultProfilesFile\":\"/tmp/DefaultProfile.json\"" - "}")); - { - Core::Directory(t2PpersistentFolder.c_str()).CreatePath(); - Core::File file(profileFN); - file.Create(); - } -} - -TEST_F(TelemetryTest, InitializePersistentFolder) -{ - ON_CALL(service, ConfigLine()) - .WillByDefault( - ::testing::Return("{" - "\"t2PersistentFolder\":\"/tmp/.t2reportprofiles/\"," - "\"defaultProfilesFile\":\"/tmp/DefaultProfile.json\"" - "}")); - { - Core::Directory(t2PpersistentFolder.c_str()).CreatePath(); - Core::File file(t2PpersistentFolder + "SomeReport"); - file.Create(); - } - -} - -TEST_F(TelemetryTest, Plugin) -{ - ON_CALL(service, ConfigLine()) - .WillByDefault( - ::testing::Return("{}")); - EXPECT_CALL(*p_rfcApiImplMock, setRFCParameter(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(3) - .WillOnce(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - return WDMP_FAILURE; - })) - .WillOnce(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - EXPECT_EQ(string(pcCallerID), _T("Telemetry")); - EXPECT_EQ(string(pcParameterName), _T("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Telemetry.FTUEReport.Enable")); - EXPECT_EQ(string(pcParameterValue), _T("false")); - EXPECT_EQ(eDataType, WDMP_BOOLEAN); - - return WDMP_SUCCESS; - })) - .WillOnce(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - EXPECT_EQ(string(pcCallerID), _T("Telemetry")); - EXPECT_EQ(string(pcParameterName), _T("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.Telemetry.FTUEReport.Enable")); - EXPECT_EQ(string(pcParameterValue), _T("true")); - EXPECT_EQ(eDataType, WDMP_BOOLEAN); - - return WDMP_SUCCESS; - })); - EXPECT_CALL(*p_telemetryApiImplMock, t2_event_s(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [](char* marker, char* value) { - EXPECT_EQ(string(marker), _T("NAME")); - EXPECT_EQ(string(value), _T("VALUE")); - return T2ERROR_SUCCESS; - })); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("setReportProfileStatus"), _T("{}"), response)); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("setReportProfileStatus"), _T("{\"status\":\"wrongvalue\"}"), response)); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("setReportProfileStatus"), _T("{\"status\":\"STARTED\"}"), response)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setReportProfileStatus"), _T("{\"status\":\"STARTED\"}"), response)); - EXPECT_EQ(response, _T("")); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("setReportProfileStatus"), _T("{\"status\":\"COMPLETE\"}"), response)); - EXPECT_EQ(response, _T("")); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("logApplicationEvent"), _T("{\"eventName\":\"NAME\"}"), response)); - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("logApplicationEvent"), _T("{\"eventValue\":\"VALUE\"}"), response)); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("logApplicationEvent"), _T("{\"eventName\":\"NAME\", \"eventValue\":\"VALUE\"}"), response)); - EXPECT_EQ(response, _T("")); - -} - -TEST_F(TelemetryTest, uploadLogsRbusOpenFailure) -{ - EXPECT_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [](rbusHandle_t* handle, char const* componentName) { - EXPECT_TRUE(nullptr != handle); - EXPECT_EQ(string(componentName), _T("TelemetryThunderPlugin")); - return RBUS_ERROR_BUS_ERROR; - })); - - EXPECT_EQ(Core::ERROR_OPENING_FAILED, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); -} - -TEST_F(TelemetryTest, uploadLogsRbusMethodFailure) -{ - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - return RBUS_ERROR_BUS_ERROR; - })); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_EQ(Core::ERROR_RPC_CALL_FAILED, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); - -} - -TEST_F(TelemetryTest, uploadLogsCallbackFailed) -{ - Core::Event onReportUpload(false, true); - - struct _rbusObject rbObject; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_BUS_ERROR, &rbObject); - - return RBUS_ERROR_SUCCESS; - })); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - EXPECT_TRUE(json->ToString(text)); - - EXPECT_EQ(text, - "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.Telemetry.onReportUpload\",\"params\":{\"telemetryUploadStatus\":\"{\\\"telemetryUploadStatus\\\":\\\"UPLOAD_FAILURE\\\"}\"}}" - ); - - onReportUpload.SetEvent(); - - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); - EXPECT_EQ(Core::ERROR_NONE, onReportUpload.Lock()); - - EVENT_UNSUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); -} - -TEST_F(TelemetryTest, uploadLogsGetValueFailure) -{ - Core::Event onReportUpload(false, true); - - struct _rbusObject rbObject; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return nullptr; - })); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - - return RBUS_ERROR_SUCCESS; - })); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - EXPECT_TRUE(json->ToString(text)); - - EXPECT_EQ(text, - "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.Telemetry.onReportUpload\",\"params\":{\"telemetryUploadStatus\":\"{\\\"telemetryUploadStatus\\\":\\\"UPLOAD_FAILURE\\\"}\"}}" - ); - - onReportUpload.SetEvent(); - - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); - EXPECT_EQ(Core::ERROR_NONE, onReportUpload.Lock()); - - EVENT_UNSUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); -} - -TEST_F(TelemetryTest, uploadLogsFailure) -{ - Core::Event onReportUpload(false, true); - - struct _rbusObject rbObject; - struct _rbusValue rbValue; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(*p_rBusApiImplMock, rbusValue_GetString(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusValue_t value, int* len) { - EXPECT_EQ(value, &rbValue); - return "FAILURE"; - })); - - ON_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return &rbValue; - })); - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - - return RBUS_ERROR_SUCCESS; - })); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - EXPECT_TRUE(json->ToString(text)); - - EXPECT_EQ(text, - "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.Telemetry.onReportUpload\",\"params\":{\"telemetryUploadStatus\":\"{\\\"telemetryUploadStatus\\\":\\\"UPLOAD_FAILURE\\\"}\"}}" - ); - - onReportUpload.SetEvent(); - - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); - EXPECT_EQ(Core::ERROR_NONE, onReportUpload.Lock()); - - EVENT_UNSUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); -} - -TEST_F(TelemetryTest, uploadLogs) -{ - Core::Event onReportUpload(false, true); - - struct _rbusObject rbObject; - struct _rbusValue rbValue; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusValue_GetString(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return( "SUCCESS")); - - ON_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return &rbValue; - })); - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - - return RBUS_ERROR_SUCCESS; - })); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - EXPECT_TRUE(json->ToString(text)); - - EXPECT_EQ(text, - "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.Telemetry.onReportUpload\",\"params\":{\"telemetryUploadStatus\":\"{\\\"telemetryUploadStatus\\\":\\\"UPLOAD_SUCCESS\\\"}\"}}" - ); - - onReportUpload.SetEvent(); - - return Core::ERROR_NONE; - })); - - EVENT_SUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("uploadReport"), _T("{}"), response)); - EXPECT_EQ(Core::ERROR_NONE, onReportUpload.Lock()); - - EVENT_UNSUBSCRIBE(0, _T("onReportUpload"), _T("org.rdk.Telemetry"), message); -} diff --git a/Tests/L1Tests/tests/test_USBDevice.cpp b/Tests/L1Tests/tests/test_USBDevice.cpp deleted file mode 100755 index fc7e60a..0000000 --- a/Tests/L1Tests/tests/test_USBDevice.cpp +++ /dev/null @@ -1,2095 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include -#include "USBDevice.h" -#include "USBDeviceImplementation.h" -#include "libUSBMock.h" -#include "ServiceMock.h" -#include "FactoriesImplementation.h" -#include // Added for file creation -#include -#include -#include -#include "COMLinkMock.h" -#include "WorkerPoolImplementation.h" -#include "WrapsMock.h" -#include "secure_wrappermock.h" -#include "ThunderPortability.h" - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -using ::testing::NiceMock; -using namespace WPEFramework; - -#define MOCK_USB_DEVICE_BUS_NUMBER_1 100 -#define MOCK_USB_DEVICE_ADDRESS_1 001 -#define MOCK_USB_DEVICE_PORT_1 123 - -#define MOCK_USB_DEVICE_BUS_NUMBER_2 101 -#define MOCK_USB_DEVICE_ADDRESS_2 002 -#define MOCK_USB_DEVICE_PORT_2 124 - -#define MOCK_USB_DEVICE_SERIAL_NO "0401805e4532973503374df52a239c898397d348" -#define MOCK_USB_DEVICE_MANUFACTURER "USB" -#define MOCK_USB_DEVICE_PRODUCT "SanDisk 3.2Gen1" -#define LIBUSB_CONFIG_ATT_BUS_POWERED 0x80 -namespace { -const string callSign = _T("USBDevice"); -} - -class USBDeviceTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - DECL_CORE_JSONRPC_CONX connection; - Core::JSONRPC::Message message; - string response; - libUSBImplMock *p_libUSBImplMock = nullptr; - Core::ProxyType USBDeviceImpl; - NiceMock comLinkMock; - NiceMock service; - PLUGINHOST_DISPATCHER* dispatcher; - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceAttached = nullptr; - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceDetached = nullptr; - Core::ProxyType workerPool; - NiceMock factoriesImplementation; - - USBDeviceTest() - : plugin(Core::ProxyType::Create()) - , handler(*(plugin)) - , INIT_CONX(1, 0) - , workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)) - { - p_libUSBImplMock = new NiceMock ; - libusbApi::setImpl(p_libUSBImplMock); - - ON_CALL(service, COMLink()) - .WillByDefault(::testing::Invoke( - [this]() { - TEST_LOG("Pass created comLinkMock: %p ", &comLinkMock); - return &comLinkMock; - })); - -#ifdef USE_THUNDER_R4 - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const RPC::Object& object, const uint32_t waitTime, uint32_t& connectionId) { - USBDeviceImpl = Core::ProxyType::Create(); - TEST_LOG("Pass created USBDeviceImpl: %p &USBDeviceImpl: %p", USBDeviceImpl, &USBDeviceImpl); - return &USBDeviceImpl; - })); -#else - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Return(USBDeviceImpl)); -#endif /*USE_THUNDER_R4 */ - - PluginHost::IFactories::Assign(&factoriesImplementation); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - - dispatcher = static_cast( - plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); - dispatcher->Activate(&service); - - /* Set all the asynchronouse event handler with libusb to handle various events*/ - ON_CALL(*p_libUSBImplMock, libusb_hotplug_register_callback(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](libusb_context *ctx, int events, int flags, int vendor_id, int product_id, int dev_class, - libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *callback_handle) { - if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == events) { - libUSBHotPlugCbDeviceAttached = cb_fn; - *callback_handle = 1; - } - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == events) { - libUSBHotPlugCbDeviceDetached = cb_fn; - *callback_handle = 2; - } - return LIBUSB_SUCCESS; - })); - - EXPECT_EQ(string(""), plugin->Initialize(&service)); - } - virtual ~USBDeviceTest() override - { - TEST_LOG("USBDeviceTest Destructor"); - - plugin->Deinitialize(&service); - - dispatcher->Deactivate(); - dispatcher->Release(); - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - - PluginHost::IFactories::Assign(nullptr); - - libusbApi::setImpl(nullptr); - if (p_libUSBImplMock != nullptr) - { - delete p_libUSBImplMock; - p_libUSBImplMock = nullptr; - } - } - - virtual void SetUp() - { - ASSERT_TRUE(libUSBHotPlugCbDeviceAttached != nullptr); - } - void Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address); - void Mock_SetSerialNumberInUSBDevicePath(); -}; - -void USBDeviceTest::Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address) -{ - ON_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillByDefault( - [bus_number, device_address](libusb_device *dev, struct libusb_device_descriptor *desc) { - if ((bus_number == dev->bus_number) && - (device_address == dev->device_address)) - { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - } - return LIBUSB_SUCCESS; - }); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillByDefault(::testing::Return(device_address)); - - ON_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillByDefault(::testing::Return(bus_number)); - - ON_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - if (device_address == MOCK_USB_DEVICE_ADDRESS_1) - { - std::string vendorFileName = "/tmp/block/sda/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "Generic" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sda/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Flash Disk" << std::endl; - outModelStream.close(); - } - - if (device_address == MOCK_USB_DEVICE_ADDRESS_2) - { - std::string vendorFileName = "/tmp/block/sdb/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "JetFlash" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sdb/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Transcend_16GB" << std::endl; - outModelStream.close(); - } -} - -void USBDeviceTest::Mock_SetSerialNumberInUSBDevicePath() -{ - std::string serialNumFileName1 = "/tmp/bus/usb/devices/100-123/serial"; - std::ofstream serialNumOutFile1(serialNumFileName1); - - if (!serialNumOutFile1) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile1 << "B32FD507" << std::endl; - serialNumOutFile1.close(); - - std::string serialNumFileName2 = "/tmp/bus/usb/devices/101-124/serial"; - std::ofstream serialNumOutFile2(serialNumFileName2); - - if (!serialNumOutFile2) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile2<< "UEUIRCXT" << std::endl; - serialNumOutFile2.close(); - - std::string serialNumFileSda = "/dev/sda"; - std::ofstream serialNumOutFileSda(serialNumFileSda); - - if (!serialNumOutFileSda) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFileSda << "B32FD507 100-123" << std::endl; - serialNumOutFileSda.close(); - - - std::string serialNumFileSdb = "/dev/sdb"; - std::ofstream serialNumOutFileSdb(serialNumFileSdb); - - if (!serialNumOutFileSdb) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFileSdb << "UEUIRCXT 101-124" << std::endl; - serialNumOutFileSdb.close(); -} - - -TEST_F(USBDeviceTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getDeviceList"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getDeviceInfo"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("bindDriver"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("unbindDriver"))); -} - -TEST_F(USBDeviceTest, Information_ReturnsEmptyString) -{ - EXPECT_EQ(plugin->Information(), string("")); -} - -/******************************************************************************************************************* -*Test function for Event:onDevicePluggedIn -*Event : onDevicePluggedIn -* Triggered when a USB device is plugged in -* -* @return (i) Exchange::IUSBDevice::USBDevice structure -* Use case coverage: -* @Success :1 -********************************************************************************************************************/ - -/** - * @brief : Validates onDevicePluggedIn event when a USB mass storage device is connected - * Verifies that the event is triggered with correct device information including - * device class (8), subclass (8), device name (100/001), and device path (/dev/sda) - * @param[in] : No parameters - * @return : JSON event with device structure containing class 8, subclass 8, name "100/001", path "/dev/sda" - * - */ -TEST_F(USBDeviceTest, OnDevicePluggedInSuccess) -{ - Core::Event onDevicePluggedIn(false, true); - - Mock_SetSerialNumberInUSBDevicePath(); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - TEST_LOG("json to string!"); - EXPECT_TRUE(json->ToString(text)); - EXPECT_EQ(text, "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.USBDevice.onDevicePluggedIn\",\"params\":{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}}"); - onDevicePluggedIn.SetEvent(); - - return Core::ERROR_NONE; - })); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - EVENT_SUBSCRIBE(0, _T("onDevicePluggedIn"), _T("org.rdk.USBDevice"), message); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - TEST_LOG("After libUSBHotPlugCbDeviceAttached"); - - EXPECT_EQ(Core::ERROR_NONE, onDevicePluggedIn.Lock()); - TEST_LOG("After EVENT_UNSUBSCRIBE"); - - EVENT_UNSUBSCRIBE(0, _T("onDevicePluggedIn"), _T("org.rdk.USBDevice"), message); - } -/*Test cases for onDevicePluggedIn ends here*/ - -/******************************************************************************************************************* -*Test function for Event:onDevicePluggedOut -*Event : onDevicePluggedOut -* Triggered when a USB drive is plugged out -* -* @return (i) Exchange::IUSBDevice::USBDevice structure -* Use case coverage: -* @Success :1 -********************************************************************************************************************/ - -/** - * @brief : Validates onDevicePluggedOut event when a USB mass storage device is disconnected - * Verifies that the event is triggered with correct device information when device is removed - * @param[in] : No parameters - * @return : JSON event with device structure containing class 8, subclass 8, name "100/001", path "/dev/sda" - * - */ -TEST_F(USBDeviceTest, onDevicePluggedOutSuccess) -{ - Core::Event onDevicePluggedOut(false, true); - - Mock_SetSerialNumberInUSBDevicePath(); - - EXPECT_CALL(service, Submit(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const uint32_t, const Core::ProxyType& json) { - string text; - EXPECT_TRUE(json->ToString(text)); - EXPECT_EQ(text, "{\"jsonrpc\":\"2.0\",\"method\":\"org.rdk.USBDevice.onDevicePluggedOut\",\"params\":{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}}"); - - onDevicePluggedOut.SetEvent(); - - return Core::ERROR_NONE; - })); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - EVENT_SUBSCRIBE(0, _T("onDevicePluggedOut"), _T("org.rdk.USBDevice"), message); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - EXPECT_EQ(Core::ERROR_NONE, onDevicePluggedOut.Lock()); - EVENT_UNSUBSCRIBE(0, _T("onDevicePluggedOut"), _T("org.rdk.USBDevice"), message); - } -/*Test cases for onDevicePluggedOut ends here*/ - -/******************************************************************************************************************* - * Test function for :getDeviceList - * getDeviceList : - * Gets a list of usb device details - * - * @return Response object containing the usb device list - * Use case coverage: - * @Success :4 (single device, multiple devices, empty list, non-mass storage devices) - * @Failure :2 (libusb errors, descriptor retrieval failures) - ********************************************************************************************************************/ - -/** - * @brief : Tests getDeviceList with a single mass storage USB device connected - * Verifies correct retrieval of device information including class, subclass, name and path - * - * @param[out] : Array with one USB device entry - * @return : ERROR_NONE with JSON array containing one device with class 8, subclass 8 - */ -TEST_F(USBDeviceTest, getDeviceListUsingWithSingleMassStorageUSBSuccessCase) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - /* Mock for Device List, 1 Device */ - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_EQ(response, string("[{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}]")); -} - -TEST_F(USBDeviceTest, GetDeviceList_EmptyList_Success) -{ - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_EQ(response, string("[]")); -} - -TEST_F(USBDeviceTest, GetDeviceList_GetDescriptorFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, GetDeviceList_NonMassStorageDevice_Success) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_HID; - desc->bDeviceClass = LIBUSB_CLASS_HID; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) { - port_numbers[0] = dev->port_number; - return 1; - } - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_EQ(response, string("[{\"deviceClass\":3,\"deviceSubclass\":3,\"deviceName\":\"100\\/001\",\"devicePath\":\"\"}]")); -} - -/** - * @brief : Tests getDeviceList with multiple mass storage USB devices connected - * Verifies correct retrieval of all devices with their respective information - * - * @param[out] : Array with multiple USB device entries - * @return : ERROR_NONE with JSON array containing two devices (100/001 and 101/002) - */ -TEST_F(USBDeviceTest, getDeviceListUsingWithMultipleMassStorageUSBSuccessCase) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2); - - /* Mock for Device List, 2 Devices */ - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 2; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_EQ(response, string("[{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"},{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"101\\/002\",\"devicePath\":\"\\/dev\\/sdb\"}]")); -} -/*Test cases for getDeviceList ends here*/ - -/******************************************************************************************************************* - * Test function for :bindDriver - * bindDriver : - * Binds the respective driver for the device. - * - * @return Success status - * Use case coverage: - * @Success :2 (driver bound successfully, driver already active) - * @Failure :5 (invalid device, open failure, kernel driver check failure, attach failure, no devices) - ********************************************************************************************************************/ - -/** - * @brief : Tests bindDriver with a valid device name - * Verifies that the kernel driver is successfully attached to the specified USB device - * - * @param[in] : deviceName - * @return : error code: ERROR_NONE - */ - TEST_F(USBDeviceTest, bindDriverSuccessCase) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2); - - /* Mock for Device List, 2 Devices */ - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 2; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - /* Call bindDriver method */ - TEST_LOG("call BindDriver"); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_DriverAlreadyActive) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(1)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_InvalidDeviceName) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_open(::testing::_, ::testing::_)) - .Times(0); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"999\\/999\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_OpenDeviceFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_open(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(0); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_KernelDriverActiveFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_AttachDriverFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_attach_kernel_driver(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NOT_FOUND)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, BindDriver_NoDevicesAvailable) -{ - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("bindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} -/*Test cases for bindDriver ends here*/ - -/******************************************************************************************************************* - * Test function for :unbindDriver - * unbindDriver : - * UnBinds the respective driver for the device. - * - * @return Success status - * Use case coverage: - * @Success :2 (driver unbound successfully, no driver active) - * @Failure :5 (invalid device, open failure, kernel driver check failure, detach failure, no devices) - ********************************************************************************************************************/ - -/** - * @brief : Tests unbindDriver with a valid device name - * Verifies that the kernel driver is successfully detached from the specified USB device - * - * @param[in] : deviceName - * @return : error code: ERROR_NONE - */ - TEST_F(USBDeviceTest, unbindDriverSuccessCase) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2); - - /* Mock for Device List, 2 Devices */ - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 2; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - /* Call unbindDriver method */ - TEST_LOG("call UnBindDriver"); - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_NoDriverActive) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_InvalidDeviceName) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_open(::testing::_, ::testing::_)) - .Times(0); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"999\\/999\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_OpenDeviceFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_open(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_ACCESS)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(0); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_KernelDriverActiveFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_DetachDriverFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(1)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_detach_kernel_driver(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NOT_FOUND)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_close(::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, UnbindDriver_NoDevicesAvailable) -{ - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("unbindDriver"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} -/*Test cases for unbindDriver ends here*/ - -/******************************************************************************************************************* - * Test function for :getDeviceInfo - * getDeviceInfo : - * Gets a usb device details - * - * @return Response object containing the usb device info - * Use case coverage: - * @Success :10 (various string descriptor scenarios including missing/empty descriptors) - * @Failure :3 (invalid device name, no devices, descriptor retrieval failures) - ********************************************************************************************************************/ -/** - * @brief : Basic getDeviceInfo tests covering error conditions - * Tests invalid device names, missing devices, and descriptor failures - * - * @param[out] : Extended USB Device Info with vendor, product, serial number details - * @return : ERROR_GENERAL for failures, ERROR_NONE for success cases - */ - - /* Basic tests */ - -TEST_F(USBDeviceTest, GetDeviceInfo_InvalidDeviceName) -{ - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"999\\/999\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, GetDeviceInfo_NoDevicesAvailable) -{ - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(0)); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceTest, GetDeviceInfo_GetDescriptorFailure) -{ - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .Times(1); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -/* Advanced tests with specific setup */ -class USBDeviceInfoTestFixture : public USBDeviceTest { -protected: - struct libusb_config_descriptor *temp_config_desc = nullptr; - - enum class StringDescriptorBehavior { - SUCCESS_ALL_DESCRIPTORS, - NO_MANUFACTURER, - NO_PRODUCT, - NO_SERIAL_NUMBER, - NEGATIVE_RETURN_WITH_ASCII_FALLBACK, - NEGATIVE_RETURN_ASCII_ALSO_FAILS, - WRONG_DESCRIPTOR_TYPE, - INVALID_DESCRIPTOR_LENGTH, - EMPTY_STRING_DESCRIPTOR, - ASCII_ZERO_LENGTH - }; - - void SetupBasicDeviceForInfo() { - Mock_SetSerialNumberInUSBDevicePath(); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = (struct libusb_device **)malloc(1 * sizeof(struct libusb_device *)); - ret[0] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) { - port_numbers[0] = dev->port_number; - return 1; - } - return 0; - }); - } - - void SetupDeviceDescriptor(bool includeManufacturer = true, bool includeProduct = true, bool includeSerialNumber = true) { - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly([includeManufacturer, includeProduct, includeSerialNumber](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = includeManufacturer ? 1 : 0; - desc->iProduct = includeProduct ? 2 : 0; - desc->iSerialNumber = includeSerialNumber ? 3 : 0; - return LIBUSB_SUCCESS; - }); - } - - void SetupConfigDescriptor() { - ON_CALL(*p_libUSBImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([this](libusb_device* pDev, struct libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - temp_config_desc = *config_desc; - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - return (int)LIBUSB_SUCCESS; - }); - } - - void SetupStringDescriptorBehavior(StringDescriptorBehavior behavior) { - switch (behavior) { - case StringDescriptorBehavior::SUCCESS_ALL_DESCRIPTORS: - ON_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if (desc_index == 0) { - data[0] = 4; - data[3] = 0x04; - data[2] = 0x09; - } else if (desc_index == 1) { - const char *buf = MOCK_USB_DEVICE_MANUFACTURER; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } else if (desc_index == 2) { - const char *buf = MOCK_USB_DEVICE_PRODUCT; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } else if (desc_index == 3) { - const char *buf = MOCK_USB_DEVICE_SERIAL_NO; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } - return (int)data[0]; - }); - break; - - case StringDescriptorBehavior::NO_MANUFACTURER: - case StringDescriptorBehavior::NO_PRODUCT: - case StringDescriptorBehavior::NO_SERIAL_NUMBER: - ON_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([behavior](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if (desc_index == 0) { - data[0] = 4; - data[3] = 0x04; - data[2] = 0x09; - } else if (desc_index == 2 && behavior != StringDescriptorBehavior::NO_PRODUCT) { - const char *buf = MOCK_USB_DEVICE_PRODUCT; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } else if (desc_index == 3 && behavior != StringDescriptorBehavior::NO_SERIAL_NUMBER) { - const char *buf = MOCK_USB_DEVICE_SERIAL_NO; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } else if (desc_index == 1 && behavior != StringDescriptorBehavior::NO_MANUFACTURER) { - const char *buf = MOCK_USB_DEVICE_MANUFACTURER; - int buffer_len = strlen(buf) * 2, j = 0, index = 2; - memset(&data[2], 0, length - 2); - while((data[index] = buf[j++]) != '\0') { - index += 2; - } - data[0] = buffer_len + 2; - } - return (int)data[0]; - }); - break; - - case StringDescriptorBehavior::NEGATIVE_RETURN_WITH_ASCII_FALLBACK: - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(LIBUSB_ERROR_PIPE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor_ascii(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length) { - if (desc_index == 1) { - strcpy((char*)data, MOCK_USB_DEVICE_MANUFACTURER); - } else if (desc_index == 2) { - strcpy((char*)data, MOCK_USB_DEVICE_PRODUCT); - } else if (desc_index == 3) { - strcpy((char*)data, MOCK_USB_DEVICE_SERIAL_NO); - } - return strlen((char*)data); - }); - break; - - case StringDescriptorBehavior::NEGATIVE_RETURN_ASCII_ALSO_FAILS: - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(LIBUSB_ERROR_PIPE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor_ascii(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(LIBUSB_ERROR_NO_DEVICE)); - break; - - case StringDescriptorBehavior::WRONG_DESCRIPTOR_TYPE: - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[0] = 10; - data[1] = LIBUSB_DT_DEVICE; - return (int)data[0]; - }); - break; - - case StringDescriptorBehavior::INVALID_DESCRIPTOR_LENGTH: - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[0] = 20; - data[1] = LIBUSB_DT_STRING; - return 10; - }); - break; - - case StringDescriptorBehavior::EMPTY_STRING_DESCRIPTOR: - ON_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if (desc_index == 0) { - data[0] = 4; - data[3] = 0x04; - data[2] = 0x09; - } else { - data[0] = 2; - } - return (int)data[0]; - }); - break; - - case StringDescriptorBehavior::ASCII_ZERO_LENGTH: - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(LIBUSB_ERROR_PIPE)); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_string_descriptor_ascii(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(0)); - break; - } - } - - void SetupGetDeviceInfoTest(StringDescriptorBehavior behavior, - bool includeManufacturer = true, - bool includeProduct = true, - bool includeSerialNumber = true) { - SetupBasicDeviceForInfo(); - SetupDeviceDescriptor(includeManufacturer, includeProduct, includeSerialNumber); - SetupConfigDescriptor(); - SetupStringDescriptorBehavior(behavior); - } -}; - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_Success_AllDescriptors) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::SUCCESS_ALL_DESCRIPTORS); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find(MOCK_USB_DEVICE_MANUFACTURER) != string::npos); - EXPECT_TRUE(response.find(MOCK_USB_DEVICE_PRODUCT) != string::npos); - EXPECT_TRUE(response.find(MOCK_USB_DEVICE_SERIAL_NO) != string::npos); - - string expectedResponse = - R"({"parentId":0,"deviceStatus":1,"deviceLevel":0,"portNumber":1,)" - R"("vendorId":4660,"productId":22136,"protocol":0,"serialNumber":"",)" - R"("device":{"deviceClass":8,"deviceSubclass":8,"deviceName":"100\/001","devicePath":""},)" - R"("flags":"AVAILABLE","features":0,"busSpeed":"High","numLanguageIds":1,)" - R"("productInfo1":{"languageId":1033,"serialNumber":"0401805e4532973503374df52a239c898397d348",)" - R"("manufacturer":"USB","product":"SanDisk 3.2Gen1"},)" - R"("productInfo2":{"languageId":0,"serialNumber":"","manufacturer":"","product":""},)" - R"("productInfo3":{"languageId":0,"serialNumber":"","manufacturer":"","product":""},)" - R"("productInfo4":{"languageId":0,"serialNumber":"","manufacturer":"","product":""}})"; - - EXPECT_EQ(response, expectedResponse); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_NoManufacturerDescriptor) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::NO_MANUFACTURER, false, true, true); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"manufacturer\":\"\"") != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_NoProductDescriptor) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::NO_PRODUCT, true, false, true); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"product\":\"\"") != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_NoSerialNumberDescriptor) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::NO_SERIAL_NUMBER, true, true, false); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"serialNumber\":\"\"") != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_GetStringDescriptorNegativeReturn) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::NEGATIVE_RETURN_WITH_ASCII_FALLBACK); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find(MOCK_USB_DEVICE_MANUFACTURER) != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_GetStringDescriptorAsciiAlsoFails) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::NEGATIVE_RETURN_ASCII_ALSO_FAILS); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"manufacturer\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"product\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"serialNumber\":\"\"") != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_WrongDescriptorType) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::WRONG_DESCRIPTOR_TYPE); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_InvalidDescriptorLength) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::INVALID_DESCRIPTOR_LENGTH); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_EQ(response, string("")); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_EmptyStringDescriptor) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::EMPTY_STRING_DESCRIPTOR); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"manufacturer\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"product\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"serialNumber\":\"\"") != string::npos); -} - -TEST_F(USBDeviceInfoTestFixture, GetDeviceInfo_GetUSBExtInfoStruct_AsciiDescriptorZeroLength) -{ - SetupGetDeviceInfoTest(StringDescriptorBehavior::ASCII_ZERO_LENGTH); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"manufacturer\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"product\":\"\"") != string::npos); - EXPECT_TRUE(response.find("\"serialNumber\":\"\"") != string::npos); -} - -/* End of getDeviceInfo tests */ - -/******************************************************************************************************************* - * Test function for :getDeviceInfo and getDeviceList with per-interface class devices - * Per-interface class devices: - * Tests devices that specify their class at the interface level rather than device level - * These devices have bDeviceClass = LIBUSB_CLASS_PER_INTERFACE (0) - * - * @return Device information with class/subclass determined from first mass storage interface - * Use case coverage: - * @Success :4 (mass storage interface, no mass storage, multiple interfaces, getDeviceInfo) - * @Failure :1 (config descriptor retrieval failure) - ********************************************************************************************************************/ -/** - * @brief : Tests getDeviceList and getDeviceInfo with per-interface class USB devices - * Verifies correct class/subclass detection when device class is defined at interface level - * Tests single and multiple interface scenarios, with and without mass storage interfaces - * - * @param[out] : USB Device Info with class determined from interface descriptors - * @return : ERROR_NONE with appropriate device class based on interfaces - */ - -class USBDevicePerInterfaceTestFixture : public USBDeviceTest { -protected: - void SetupPerInterfaceDeviceBase(uint8_t num_interfaces, const std::vector>& interface_classes) { - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - libusb_device **ret = (libusb_device **)malloc(1 * sizeof(libusb_device *)); - ret[0] = (libusb_device *)malloc(sizeof(libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceClass = LIBUSB_CLASS_PER_INTERFACE; - desc->bDeviceSubClass = 0; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = 1; - desc->iProduct = 2; - desc->iSerialNumber = 3; - desc->bDeviceProtocol = 0; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) { - port_numbers[0] = dev->port_number; - return 1; - } - return 0; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_config_descriptor(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([num_interfaces, interface_classes](libusb_device *dev, uint8_t config_index, libusb_config_descriptor **config) { - libusb_config_descriptor *cfg = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - cfg->bNumInterfaces = num_interfaces; - - libusb_interface *interfaces = (libusb_interface *)malloc(num_interfaces * sizeof(libusb_interface)); - - for (uint8_t i = 0; i < num_interfaces; i++) { - interfaces[i].num_altsetting = 1; - - libusb_interface_descriptor *altsetting = (libusb_interface_descriptor *)malloc(sizeof(libusb_interface_descriptor)); - - if (i < interface_classes.size()) { - altsetting->bInterfaceClass = interface_classes[i].first; - altsetting->bInterfaceSubClass = interface_classes[i].second; - } else { - altsetting->bInterfaceClass = LIBUSB_CLASS_HID; - altsetting->bInterfaceSubClass = 0; - } - - interfaces[i].altsetting = altsetting; - } - - cfg->interface = interfaces; - *config = cfg; - - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_free_config_descriptor(::testing::_)) - .WillOnce([num_interfaces](libusb_config_descriptor *config) { - if (config) { - if (config->interface) { - for (uint8_t i = 0; i < num_interfaces; i++) { - if (config->interface[i].altsetting) { - free((void*)config->interface[i].altsetting); - } - } - free((void*)config->interface); - } - free(config); - } - }); - } - - void SetupGetDeviceInfoMocks() { - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - ON_CALL(*p_libUSBImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device* pDev, libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - return (int)LIBUSB_SUCCESS; - }); - - ON_CALL(*p_libUSBImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if (desc_index == 0) { - data[0] = 4; - data[2] = 0x09; - data[3] = 0x04; - } else { - data[0] = 10; - for (int i = 2; i < 10; i += 2) { - data[i] = 'T'; - data[i+1] = 0; - } - } - return (int)data[0]; - }); - } - - void SetupPerInterfaceDevice(uint8_t num_interfaces, const std::vector>& interface_classes) { - SetupPerInterfaceDeviceBase(num_interfaces, interface_classes); - } - - void SetupPerInterfaceDeviceConfigFailure() { - Mock_SetSerialNumberInUSBDevicePath(); - - ON_CALL(*p_libUSBImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_context *ctx, libusb_device ***list) { - libusb_device **ret = (libusb_device **)malloc(1 * sizeof(libusb_device *)); - ret[0] = (libusb_device *)malloc(sizeof(libusb_device)); - ret[0]->bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - ret[0]->device_address = MOCK_USB_DEVICE_ADDRESS_1; - ret[0]->port_number = MOCK_USB_DEVICE_PORT_1; - *list = ret; - return (ssize_t)1; - }); - - ON_CALL(*p_libUSBImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault([](libusb_device **list, int unref_devices) { - free(list[0]); - free(list); - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceClass = LIBUSB_CLASS_PER_INTERFACE; - desc->bDeviceSubClass = 0; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly([](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) { - port_numbers[0] = dev->port_number; - return 1; - } - return 0; - }); - - EXPECT_CALL(*p_libUSBImplMock, libusb_get_config_descriptor(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(LIBUSB_ERROR_NOT_FOUND)); - } - - void SetupPerInterfaceDeviceForGetDeviceInfo(uint8_t num_interfaces, const std::vector>& interface_classes) { - SetupPerInterfaceDeviceBase(num_interfaces, interface_classes); - SetupGetDeviceInfoMocks(); - } -}; - -TEST_F(USBDevicePerInterfaceTestFixture, GetDeviceList_PerInterfaceClass_MassStorage_Success) -{ - std::vector> interfaces = {{LIBUSB_CLASS_MASS_STORAGE, 6}}; - SetupPerInterfaceDevice(1, interfaces); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_TRUE(response.find("\"deviceClass\":8") != string::npos); - EXPECT_TRUE(response.find("\"deviceSubclass\":6") != string::npos); -} - -TEST_F(USBDevicePerInterfaceTestFixture, GetDeviceList_PerInterfaceClass_NoMassStorage_Success) -{ - std::vector> interfaces = {{LIBUSB_CLASS_HID, 0}}; - SetupPerInterfaceDevice(1, interfaces); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_TRUE(response.find("\"deviceClass\":0") != string::npos); - EXPECT_TRUE(response.find("\"devicePath\":\"\"") != string::npos); -} - -TEST_F(USBDevicePerInterfaceTestFixture, GetDeviceList_PerInterfaceClass_GetConfigDescriptorFailure) -{ - SetupPerInterfaceDeviceConfigFailure(); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_TRUE(response.find("\"deviceClass\":0") != string::npos); -} - -TEST_F(USBDevicePerInterfaceTestFixture, GetDeviceInfo_PerInterfaceClass_MassStorage_Success) -{ - std::vector> interfaces = {{LIBUSB_CLASS_MASS_STORAGE, 6}}; - SetupPerInterfaceDeviceForGetDeviceInfo(1, interfaces); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceInfo"), _T("{\"deviceName\":\"100\\/001\"}"), response)); - EXPECT_TRUE(response.find("\"deviceClass\":8") != string::npos); - EXPECT_TRUE(response.find("\"deviceSubclass\":6") != string::npos); -} - -TEST_F(USBDevicePerInterfaceTestFixture, GetDeviceList_PerInterfaceClass_MultipleInterfaces_Success) -{ - std::vector> interfaces = { - {LIBUSB_CLASS_HID, 0}, - {LIBUSB_CLASS_MASS_STORAGE, 6} - }; - SetupPerInterfaceDevice(2, interfaces); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - EXPECT_TRUE(response.find("\"deviceClass\":8") != string::npos); -} diff --git a/Tests/L1Tests/tests/test_USBMassStorage.cpp b/Tests/L1Tests/tests/test_USBMassStorage.cpp deleted file mode 100755 index 8b4aa25..0000000 --- a/Tests/L1Tests/tests/test_USBMassStorage.cpp +++ /dev/null @@ -1,1133 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "USBMassStorage.h" -#include "USBMassStorageImplementation.h" -#include "WorkerPoolImplementation.h" -#include "ServiceMock.h" -#include "USBDeviceMock.h" -#include "COMLinkMock.h" -#include "WrapsMock.h" -#include "ThunderPortability.h" -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -using ::testing::NiceMock; -using namespace WPEFramework; - -class USBMassStorageTest : public ::testing::Test { -protected: - Core::ProxyType plugin; - Core::JSONRPC::Handler& handler; - Core::JSONRPC::Context connection; - NiceMock service; - Core::JSONRPC::Message message; - NiceMock comLinkMock; - Core::ProxyType workerPool; - Core::ProxyType USBMassStorageImpl; - Exchange::IUSBDevice::INotification *USBDeviceNotification_cb = nullptr; - Exchange::IUSBMassStorage::INotification *notification = nullptr; - string response; - USBDeviceMock *p_usbDeviceMock = nullptr; - WrapsImplMock *p_wrapsImplMock = nullptr; - ServiceMock *p_serviceMock = nullptr; - USBMassStorageTest() - : plugin(Core::ProxyType::Create()) - , handler(*plugin) - , connection(1,0,"") - , workerPool(Core::ProxyType::Create( - 2, Core::Thread::DefaultStackSize(), 16)) - { - p_serviceMock = new NiceMock ; - - p_usbDeviceMock = new NiceMock ; - - p_wrapsImplMock = new NiceMock ; - Wraps::setImpl(p_wrapsImplMock); - - EXPECT_CALL(service, QueryInterfaceByCallsign(::testing::_, ::testing::_)) - .WillOnce(testing::Return(p_usbDeviceMock)); - - ON_CALL(*p_usbDeviceMock, Register(::testing::_)) - .WillByDefault(::testing::Invoke( - [&](Exchange::IUSBDevice::INotification *notification){ - USBDeviceNotification_cb = notification; - return Core::ERROR_NONE;; - })); - - ON_CALL(comLinkMock, Instantiate(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const RPC::Object& object, const uint32_t waitTime, uint32_t& connectionId) { - USBMassStorageImpl = Core::ProxyType::Create(); - return &USBMassStorageImpl; - })); - - Core::IWorkerPool::Assign(&(*workerPool)); - workerPool->Run(); - - plugin->Initialize(&service); - } - - virtual ~USBMassStorageTest() override - { - plugin->Deinitialize(&service); - - Core::IWorkerPool::Assign(nullptr); - workerPool.Release(); - - - if (p_serviceMock != nullptr) - { - delete p_serviceMock; - p_serviceMock = nullptr; - } - - if (p_usbDeviceMock != nullptr) - { - delete p_usbDeviceMock; - p_usbDeviceMock = nullptr; - } - - Wraps::setImpl(nullptr); - if (p_wrapsImplMock != nullptr) - { - delete p_wrapsImplMock; - p_wrapsImplMock = nullptr; - } - } -}; - -TEST_F(USBMassStorageTest, RegisteredMethods) -{ - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getDeviceList"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getMountPoints"))); - EXPECT_EQ(Core::ERROR_NONE, handler.Exists(_T("getPartitionInfo"))); -} - -TEST_F(USBMassStorageTest, OnDevicePluggedIn) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - Exchange::IUSBDevice::USBDevice usbDevice2; - usbDevice1.deviceClass = 8; - usbDevice1.deviceSubclass = 8; - usbDevice1.deviceName = "sda"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - USBMassStorageImpl->OnDevicePluggedIn(usbDevice1); - -} - -TEST_F(USBMassStorageTest, OnDevicePluggedOut) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - Exchange::IUSBDevice::USBDevice usbDevice2; - usbDevice1.deviceClass = 8; - usbDevice1.deviceSubclass = 8; - usbDevice1.deviceName = "sda"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - USBMassStorageImpl->OnDevicePluggedOut(usbDevice1); - -} - -TEST_F(USBMassStorageTest, getdevicelistFailed_devicelist_empty) -{ - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); -} - -TEST_F(USBMassStorageTest, getdevicelistFailed_GetDevicePath_empty_failed) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "Device1"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - -} - -TEST_F(USBMassStorageTest, getdevicelistFailed__empty_failed) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - //usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "Device1"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - -} - -TEST_F(USBMassStorageTest, getdevicelistFailed_GetDeviceList_failed) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "Device1"; - usbDevice1.devicePath = ""; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_GENERAL; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - -} - -TEST_F(USBMassStorageTest, getdevicelistFailed_instance_null_failed) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "Device1"; - usbDevice1.devicePath = ""; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - //USBMassStorageImpl.Reset(); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_empty_parameter) -{ - EXPECT_EQ(Core::ERROR_INVALID_PARAMETER, handler.Invoke(connection, _T("getMountPoints"), _T("{}"), response)); -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_devicename_empty) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - EXPECT_EQ(Core::ERROR_INVALID_PARAMETER, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\"}"), response)); - -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_devicename_mismatch) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - EXPECT_EQ(ERROR_INVALID_DEVICENAME, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001\"}"), response)); - -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_umount_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return -1; - }); - - EXPECT_EQ(ERROR_INVALID_DEVICENAME, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001\"}"), response)); - -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_mount_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getMountPointsFailed_mkdir_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFailed_mountpoints_empty) -{ - EXPECT_EQ(Core::ERROR_INVALID_PARAMETER, handler.Invoke(connection, _T("getPartitionInfo"), _T("{}"), response)); -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_statfs_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_statvfs_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - -EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_devicepath_empty) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - - EXPECT_EQ(ERROR_INVALID_MOUNTPOINT, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/medis/usb1\"}"), response)); - - usbDeviceList.clear(); -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_opencall_fail) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int flags, mode_t mode) { - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_PartitionSize_fails) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int flags, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - if (request == BLKGETSIZE64) { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 *1024; - } - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_NumberOfSectors_fails) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int flags, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, BLKGETSIZE64, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 * 1024; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, BLKGETSIZE, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, getPartitionInfoFail_SectorSize_fails) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int flags, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, BLKGETSIZE64, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 * 1024; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, BLKGETSIZE, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, BLKSSZGET, ::testing::_)) - .WillOnce([](int fd, unsigned long request, void* argp) -> int { - *(reinterpret_cast(argp)) = 512; - return -1; - }); - - EXPECT_EQ(Core::ERROR_GENERAL, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -/*Success case for getdevicelist, getMountPoints, getPartitionInfo*/ -TEST_F(USBMassStorageTest, USBMassStorage_Succeed) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response)); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statfs* buf) -> int { - if (buf != nullptr) { - buf->f_type = 0x565a; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillOnce([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int flags, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](int fd, unsigned long request, void* argp) -> int { - if (request == BLKGETSIZE64) { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 *1024; - } - else if (request == BLKGETSIZE) { - *(reinterpret_cast(argp)) = 1024; - } - else if (request == BLKSSZGET) { - *(reinterpret_cast(argp)) = 512; - } - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getPartitionInfo"), _T("{\"mountPath\": \"/tmp/media/usb1\"}"), response)); - - usbDeviceList.clear(); - -} - -TEST_F(USBMassStorageTest, USBMassStorage_Succeed_MountPoints) -{ - std::list usbDeviceList; - Exchange::IUSBDevice::USBDevice usbDevice1; - usbDevice1.deviceClass = LIBUSB_CLASS_MASS_STORAGE; - usbDevice1.deviceSubclass = 0x12; - usbDevice1.deviceName = "001/002"; - usbDevice1.devicePath = "/dev/sda"; - usbDeviceList.emplace_back(usbDevice1); - - auto mockIterator = Core::Service>::Create(usbDeviceList); - - EXPECT_CALL(*p_usbDeviceMock, GetDeviceList(testing::_)) - .WillOnce([&](Exchange::IUSBDevice::IUSBDeviceIterator*& devices) { - devices = mockIterator; - return Core::ERROR_NONE; // Simulate successful return - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getDeviceList"), _T("{}"), response)); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = "/tmp/media/usb" + std::to_string(index); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response)); - - EXPECT_EQ(Core::ERROR_NONE, handler.Invoke(connection, _T("getMountPoints"), _T("{\"deviceName\": \"001/002\"}"), response)); - - usbDeviceList.clear(); - -} - diff --git a/Tests/L1Tests/tests/test_UtilsFile.cpp b/Tests/L1Tests/tests/test_UtilsFile.cpp deleted file mode 100644 index ed41f3a..0000000 --- a/Tests/L1Tests/tests/test_UtilsFile.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "Module.h" - -#include "UtilsFile.h" - -namespace { -const uint8_t bytes[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xFE, 0x03, 0x20, 0x04, 0x00, 0x01 }; -} -#include "ThunderPortability.h" - -using namespace WPEFramework; - -TEST(UtilsFileTest, createFolder_createFile_moveFile_verifyFile) -{ - Core::Directory dir(_T("/tmp/UtilsFileTest")); - -#ifdef USE_THUNDER_R4 - EXPECT_TRUE(dir.Destroy()); -#else - EXPECT_TRUE(dir.Destroy(false)); -#endif /*USE_THUNDER_R4 */ - ASSERT_TRUE(dir.CreatePath()); - - Core::File file(string(_T("/tmp/UtilsFileTest/file"))); - - EXPECT_FALSE(file.Exists()); - EXPECT_TRUE(file.Create()); - EXPECT_EQ(sizeof(bytes), file.Write(bytes, sizeof(bytes))); - - Core::File file2(string(_T("/tmp/UtilsFileTest/destination/for/new/file"))); - - EXPECT_FALSE(file2.Exists()); - EXPECT_TRUE(Utils::MoveFile(file.Name(), file2.Name())); - file.LoadFileInfo(); - file2.LoadFileInfo(); - EXPECT_FALSE(file.Exists()); - EXPECT_TRUE(file2.Exists()); - EXPECT_TRUE(file2.Open(true)); - - uint8_t buffer[2 * sizeof(bytes)]; - - EXPECT_EQ(sizeof(bytes), file2.Read(buffer, 2 * sizeof(bytes))); - EXPECT_EQ(0, memcmp(buffer, bytes, sizeof(bytes))); -} diff --git a/Tests/L2Tests/CMakeLists.txt b/Tests/L2Tests/CMakeLists.txt index 66c498b..df03e5e 100755 --- a/Tests/L2Tests/CMakeLists.txt +++ b/Tests/L2Tests/CMakeLists.txt @@ -22,54 +22,10 @@ set(THUNDER_PORT 9998) find_package(${NAMESPACE}Plugins REQUIRED) -if(PLUGIN_MIGRATION) - set(SRC_FILES ${SRC_FILES} tests/Migration_L2Test.cpp) -endif() - -if (PLUGIN_ANALYTICS) - set(SRC_FILES ${SRC_FILES} tests/Analytics_L2Test.cpp) -endif() - -if(PLUGIN_APPMANAGER) - set(SRC_FILES ${SRC_FILES} tests/AppManager_L2Test.cpp) -endif() - -if(PLUGIN_TELEMETRY) - set(SRC_FILES ${SRC_FILES} tests/Telemetry_L2Test.cpp) -endif() - -if(PLUGIN_USBDEVICE) - set(SRC_FILES ${SRC_FILES} tests/UsbDevice_L2Test.cpp) -endif() - -if(PLUGIN_USB_MASS_STORAGE) - set(SRC_FILES ${SRC_FILES} tests/UsbMassStorage_L2Test.cpp) -endif() - if(PLUGIN_USERSETTINGS) set(SRC_FILES ${SRC_FILES} tests/UserSettings_L2Test.cpp) endif() -if(PLUGIN_USBACCESS) - set(SRC_FILES ${SRC_FILES} tests/UsbAccess_L2Test.cpp) -endif() - -if(PLUGIN_STORAGE_MANAGER) - set(SRC_FILES ${SRC_FILES} tests/StorageManager_L2Test.cpp) -endif() - -if(PLUGIN_SHAREDSTORAGE) - set(SRC_FILES ${SRC_FILES} tests/SharedStorage_L2Test.cpp) -endif() - -if(PLUGIN_RESOURCEMANAGER) - set(SRC_FILES ${SRC_FILES} tests/ResourceManager_L2Test.cpp) -endif() - -if(PLUGIN_OCICONTAINER) - set(SRC_FILES ${SRC_FILES} tests/OCIContainer_L2Test.cpp) -endif() - add_library(${MODULE_NAME} SHARED ${SRC_FILES}) set_target_properties(${MODULE_NAME} PROPERTIES diff --git a/Tests/L2Tests/tests/Analytics_L2Test.cpp b/Tests/L2Tests/tests/Analytics_L2Test.cpp deleted file mode 100755 index 520beb3..0000000 --- a/Tests/L2Tests/tests/Analytics_L2Test.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "deepSleepMgr.h" -#include "PowerManagerMock.h" -#include "PowerManagerHalMock.h" -#include "MfrMock.h" - -#define TEST_LOG(x, ...) \ - fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); \ - fflush(stderr); - -#define JSON_TIMEOUT (1000) -#define ANALYTICS_CALLSIGN _T("org.rdk.Analytics") -#define ANALYTICSL2TEST_CALLSIGN _T("L2tests.1") - -#define SERVER_IP "127.0.0.1" -#define SERVER_PORT 12345 -#define SERVER_TIMEOUT_SEC (30) - -#define EVENTS_MAP "[ \ - { \ - \"event_name\":\"L2MapTestEvent\", \ - \"event_source\":\"L2Test\", \ - \"mapped_event_name\":\"L2TestEventMappedGeneric\" \ - }, \ - { \ - \"event_name\":\"L2MapTestEvent\", \ - \"event_source\":\"L2Test\", \ - \"event_source_version\":\"1.0.0\", \ - \"event_version\":\"1\", \ - \"mapped_event_name\":\"L2TestEventMappedExact\" \ - }, \ - { \ - \"event_name\":\"L2MapTestEvent\", \ - \"event_source\":\"L2Test\", \ - \"event_version\":\"1\", \ - \"mapped_event_name\":\"L2TestEventMappedGenericSourceVersion\" \ - }, \ - { \ - \"event_name\":\"L2MapTestEvent\", \ - \"event_source\":\"L2Test\", \ - \"event_source_version\":\"1.0.0\", \ - \"mapped_event_name\":\"L2TestEventMappedGenericVersion\" \ - } \ - ]" - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; - -char gPipeBuffer[4 * 1024]; - -class ServerMock { -public: - ServerMock() - : mSocket(-1) - { - memset(&mAddress, 0, sizeof(mAddress)); - } - - ~ServerMock() - { - if (mSocket != -1) { - close(mSocket); - } - } - - bool Start() - { - mSocket = socket(AF_INET, SOCK_STREAM, 0); - if (mSocket == -1) { - TEST_LOG("Socket error"); - return false; - } - - int optval = 1; - if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { - TEST_LOG("Failed to set SO_REUSEADDR"); - close(mSocket); - return false; - } - - mAddress.sin_family = AF_INET; - mAddress.sin_addr.s_addr = inet_addr(SERVER_IP); - mAddress.sin_port = htons(SERVER_PORT); - - if (bind(mSocket, (struct sockaddr*)&mAddress, sizeof(mAddress)) == -1) { - TEST_LOG("Bind error"); - close(mSocket); - return false; - } - - if (listen(mSocket, 1) == -1) { - TEST_LOG("Listen error"); - close(mSocket); - return false; - } - - return true; - } - - string AwaitData(uint32_t timeoutSec, string errCodeResp = "200 OK") - { - fd_set readfds; - struct timeval timeout; - timeout.tv_sec = timeoutSec; - timeout.tv_usec = 0; - string ret; - - FD_ZERO(&readfds); - FD_SET(mSocket, &readfds); - - int result = select(mSocket + 1, &readfds, NULL, NULL, &timeout); - if (result == -1) { - TEST_LOG("Select error"); - return ret; - } else if (result == 0) { - TEST_LOG("Timeout occurred! No data received.\n"); - return ret; - } - - int client_socket; - struct sockaddr_in client_address; - socklen_t client_address_len = sizeof(client_address); - - client_socket = accept(mSocket, (struct sockaddr*)&client_address, &client_address_len); - if (client_socket == -1) { - TEST_LOG("Accept error"); - return ret; - } - struct timeval client_timeout; - client_timeout.tv_sec = timeoutSec; - client_timeout.tv_usec = 0; - - setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&client_timeout, sizeof(client_timeout)); - char rxBuf[32 * 1024]; - ssize_t bytes_received = recv(client_socket, rxBuf, sizeof(rxBuf) - 1, 0); - if (bytes_received == -1) { - TEST_LOG("Recv error"); - } else { - rxBuf[bytes_received] = '\0'; - TEST_LOG("Received data: %s\n", rxBuf); - - // Send HTTP code response - std::string httpResponse = "HTTP/1.1 " + errCodeResp + "\r\n" - "Content-Type: application/json\r\n" - "Content-Length: 0\r\n" - "\r\n"; - - send(client_socket, httpResponse.c_str(), httpResponse.length(), 0); - // Remove header from received data - char* start = strstr(rxBuf, "\r\n\r\n"); - if (start != NULL) { - ret = string(start + 4); - } - } - - close(client_socket); - - return ret; - } - -private: - int mSocket; - struct sockaddr_in mAddress; -}; - -class AnalyticsTest : public L2TestMocks { -protected: - virtual ~AnalyticsTest() override; - -public: - AnalyticsTest(); -}; - -extern "C" int __real_pclose(FILE* pipe); - -AnalyticsTest::AnalyticsTest() - : L2TestMocks() -{ - Core::JSONRPC::Message message; - string response; - uint32_t status = Core::ERROR_GENERAL; - EXPECT_CALL(*p_powerManagerHalMock, PLAT_DS_INIT()) - .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_INIT()) - .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetWakeupSrc(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); - - ON_CALL(*p_rfcApiImplMock, getRFCParameter(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, RFC_ParamData_t* pstParamData) { - if (strcmp("RFC_DATA_ThermalProtection_POLL_INTERVAL", pcParameterName) == 0) { - strcpy(pstParamData->value, "2"); - return WDMP_SUCCESS; - } else if (strcmp("RFC_ENABLE_ThermalProtection", pcParameterName) == 0) { - strcpy(pstParamData->value, "true"); - return WDMP_SUCCESS; - } else if (strcmp("RFC_DATA_ThermalProtection_DEEPSLEEP_GRACE_INTERVAL", pcParameterName) == 0) { - strcpy(pstParamData->value, "6"); - return WDMP_SUCCESS; - } else { - /* The default threshold values will assign, if RFC call failed */ - return WDMP_FAILURE; - } - })); - - EXPECT_CALL(*p_mfrMock, mfrSetTempThresholds(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](int high, int critical) { - EXPECT_EQ(high, 100); - EXPECT_EQ(critical, 110); - return mfrERR_NONE; - })); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_GetPowerState(::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t* powerState) { - *powerState = PWRMGR_POWERSTATE_OFF; // by default over boot up, return PowerState OFF - return PWRMGR_SUCCESS; - })); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetPowerState(::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t powerState) { - // All tests are run without settings file - // so default expected power state is ON - return PWRMGR_SUCCESS; - })); - - EXPECT_CALL(*p_mfrMock, mfrGetTemperature(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](mfrTemperatureState_t* curState, int* curTemperature, int* wifiTemperature) { - *curTemperature = 90; // safe temperature - *curState = (mfrTemperatureState_t)0; - *wifiTemperature = 25; - return mfrERR_NONE; - })); - - // Activate plugin in constructor - status = ActivateService("org.rdk.PowerManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = ActivateService("org.rdk.System"); - EXPECT_EQ(Core::ERROR_NONE, status); - - JsonObject paramsJson; - JsonObject resultJson; - - - // Set SystemService fake values - paramsJson.Clear(); - paramsJson["territory"] = "USA"; - paramsJson["region"] = "US-USA"; - status = InvokeServiceMethod("org.rdk.System", "setTerritory", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - // Mock System.getDeviceInfo by creating custom /etc/device.properties - std::ofstream deviceProperties("/etc/device.properties"); - deviceProperties << "BUILD_TYPE=dev\n"; - deviceProperties << "FORCE_MTLS=true\n"; - deviceProperties << "DEVICE_NAME=PLATCO\nDEVICE_TYPE=mediaclient\nMFG_NAME=Element\nWIFI_SUPPORT=true\n"; - deviceProperties << "MOCA_INTERFACE=true\nWIFI_INTERFACE=wlan0\nMOCA_INTERFACE=eth0\nETHERNET_INTERFACE=eth0\n"; - deviceProperties << "RDK_PROFILE=TV"; - deviceProperties.close(); - - - - // Mock event mapping file - std::ofstream eventsMapFile("/tmp/AnalyticsEventsMap.json"); - eventsMapFile << EVENTS_MAP; - eventsMapFile.close(); - - // Activate Analytics plugin - status = ActivateService("org.rdk.Analytics"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -AnalyticsTest::~AnalyticsTest() -{ - uint32_t status = Core::ERROR_GENERAL; - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_TERM()) - .WillOnce(::testing::Return(PWRMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_DS_TERM()) - .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); - - status = DeactivateService("org.rdk.PowerManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.System"); - EXPECT_EQ(Core::ERROR_NONE, status); - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_)) - .WillByDefault(::testing::Return(RBUS_ERROR_SUCCESS)); - - status = DeactivateService("org.rdk.Analytics"); - EXPECT_EQ(Core::ERROR_NONE, status); - - sleep(5); - - int file_status = remove("/tmp/AnalyticsStore.db"); - // Check if the file has been successfully removed - if (file_status != 0) { - TEST_LOG("Error deleting file[/tmp/AnalyticsStore.db]"); - } else { - TEST_LOG("File[/tmp/AnalyticsStore.db] successfully deleted"); - } - - file_status = remove("/opt/persistent/timeZoneDST"); - // Check if the file has been successfully removed - if (file_status != 0) { - TEST_LOG("Error deleting file[/opt/persistent/timeZoneDST]"); - } else { - TEST_LOG("File[/opt/persistent/timeZoneDST] successfully deleted"); - } - - file_status = remove("/tmp/AnalyticsEventsMap.json"); - // Check if the file has been successfully removed - if (file_status != 0) { - TEST_LOG("Error deleting file[/tmp/AnalyticsEventsMap.json]"); - } else { - TEST_LOG("File[/tmp/AnalyticsEventsMap.json] successfully deleted"); - } -} - -TEST_F(AnalyticsTest, SendAndReceiveSignleEventQueued) -{ - JsonObject paramsJson; - JsonObject resultJson; - paramsJson["eventName"] = "L2TestEvent"; - paramsJson["eventVersion"] = "1"; - paramsJson["eventSource"] = "L2Test"; - paramsJson["eventSourceVersion"] = "1.0.0"; - JsonObject eventPayload; - eventPayload["data"] = "random data"; - paramsJson["eventPayload"] = eventPayload; - - ServerMock server; - EXPECT_TRUE(server.Start()); - - uint32_t status = InvokeServiceMethod("org.rdk.Analytics", "sendEvent", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - // TimeZone not set, check if data will not come - string eventMsg = server.AwaitData(SERVER_TIMEOUT_SEC); - EXPECT_EQ(eventMsg, ""); - - // Set TimeZone to FINAL what allows event to be decorated and sent to server - paramsJson.Clear(); - paramsJson["timeZone"] = "America/New_York"; - paramsJson["accuracy"] = "FINAL"; - status = InvokeServiceMethod("org.rdk.System", "setTimeZoneDST", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - eventMsg = server.AwaitData(SERVER_TIMEOUT_SEC); - EXPECT_NE(eventMsg, ""); - - // Check if the event message contains the expected fields - JsonArray eventArray; - eventArray.FromString(eventMsg); - EXPECT_EQ(eventArray.Length(), 1); - JsonObject eventObj = eventArray[0].Object(); - JsonObject eventPayloadObj = eventObj["eventPayload"].Object(); - EXPECT_TRUE(eventPayloadObj.HasLabel("data")); - EXPECT_EQ(eventPayloadObj["data"].String(), "random data"); -} - -TEST_F(AnalyticsTest, EventsMapping) -{ - JsonObject paramsJson; - JsonObject resultJson; - - // exact mapping - paramsJson["eventName"] = "L2MapTestEvent"; - paramsJson["eventVersion"] = "1"; - paramsJson["eventSource"] = "L2Test"; - paramsJson["eventSourceVersion"] = "1.0.0"; - - JsonObject eventPayload; - eventPayload["data"] = "random data"; - paramsJson["eventPayload"] = eventPayload; - - uint32_t status = InvokeServiceMethod("org.rdk.Analytics", "sendEvent", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - // generic mapping - paramsJson["eventName"] = "L2MapTestEvent"; - paramsJson["eventVersion"] = "2"; - paramsJson["eventSource"] = "L2Test"; - paramsJson["eventSourceVersion"] = "1.0.1"; - status = InvokeServiceMethod("org.rdk.Analytics", "sendEvent", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - // generic mapping by source version - paramsJson["eventName"] = "L2MapTestEvent"; - paramsJson["eventVersion"] = "2"; - paramsJson["eventSource"] = "L2Test"; - paramsJson["eventSourceVersion"] = "1.0.0"; - status = InvokeServiceMethod("org.rdk.Analytics", "sendEvent", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - // generic mapping by event version - paramsJson["eventName"] = "L2MapTestEvent"; - paramsJson["eventVersion"] = "1"; - paramsJson["eventSource"] = "L2Test"; - paramsJson["eventSourceVersion"] = "1.0.1"; - status = InvokeServiceMethod("org.rdk.Analytics", "sendEvent", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - ServerMock server; - EXPECT_TRUE(server.Start()); - - // Set TimeZone to FINAL what allows event to be decorated and sent to server - paramsJson.Clear(); - paramsJson["timeZone"] = "America/New_York"; - paramsJson["accuracy"] = "FINAL"; - status = InvokeServiceMethod("org.rdk.System", "setTimeZoneDST", paramsJson, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - - string eventsMsg = server.AwaitData(SERVER_TIMEOUT_SEC); - - // Check if the event message contains the expected fields - JsonArray eventArray; - eventArray.FromString(eventsMsg); - int retry = 5; - while (eventArray.Length() < 4 && retry-- > 0) { - // If not all events are received, wait for the rest - string eventsMsg2 = server.AwaitData(SERVER_TIMEOUT_SEC); - JsonArray eventArray2; - eventArray2.FromString(eventsMsg2); - for (int i = 0; i < eventArray2.Length(); ++i) { - eventArray.Add(eventArray2[i]); - } - } - EXPECT_EQ(eventArray.Length(), 4); - - if (eventArray.Length() == 4) { - JsonObject eventObj = eventArray[0].Object(); - EXPECT_TRUE(eventObj.HasLabel("eventName")); - EXPECT_EQ(eventObj["eventName"].String(), "L2TestEventMappedExact"); - - eventObj = eventArray[1].Object(); - EXPECT_TRUE(eventObj.HasLabel("eventName")); - EXPECT_EQ(eventObj["eventName"].String(), "L2TestEventMappedGeneric"); - - eventObj = eventArray[2].Object(); - EXPECT_TRUE(eventObj.HasLabel("eventName")); - EXPECT_EQ(eventObj["eventName"].String(), "L2TestEventMappedGenericVersion"); - - eventObj = eventArray[3].Object(); - EXPECT_TRUE(eventObj.HasLabel("eventName")); - EXPECT_EQ(eventObj["eventName"].String(), "L2TestEventMappedGenericSourceVersion"); - } -} diff --git a/Tests/L2Tests/tests/AppManager_L2Test.cpp b/Tests/L2Tests/tests/AppManager_L2Test.cpp deleted file mode 100755 index f75586c..0000000 --- a/Tests/L2Tests/tests/AppManager_L2Test.cpp +++ /dev/null @@ -1,1466 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include -#include - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -/* Notification verification in tests will be disabled in Phase 1 since notification callback functionality will not be implemented. - * Just adding the notification framework at this time; formalization is required when adding the implementation. then remove below define - */ -//#define ENABLE_NOTIFICATION_VERIFICATION - -/* In phase 1, state change will not happened so,few test case it will fail, now commented the verification, once life cyle state change - * is ready then remove this define and enable the verification. - */ -//#define ENABLE_LIFECYCLE_STATE_CHANGE_VERIFICATION - -#define JSON_TIMEOUT (1000) -#define APPMANAGER_CALLSIGN _T("org.rdk.AppManager") -#define APPMANAGERL2TEST_CALLSIGN _T("L2tests.1") - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::IStore2; -using ::WPEFramework::Exchange::IAppManager; - -MATCHER_P(MatchRequestStatusString, data, "") -{ - std::string actual = arg; - TEST_LOG("Expected: %s, Actual: %s", data.c_str(), actual.c_str()); - EXPECT_STREQ(data.c_str(), actual.c_str()); - return data == actual; -} - -MATCHER_P(MatchRequestStatusNumber, data, "") -{ - uint32_t actual = arg; - TEST_LOG("Expected: %u, Actual: %u", data, actual); - EXPECT_EQ(data, actual); - return data == actual; -} - -MATCHER_P(MatchRequestStatusBool, expected, "") -{ - bool actual = arg; - std::string expected_str = expected ? "true" : "false"; - std::string actual_str = actual ? "true" : "false"; - TEST_LOG("Expected: %s, Actual: %s", expected_str.c_str(), actual_str.c_str()); - EXPECT_STREQ(expected_str.c_str(), actual_str.c_str()); - return expected == actual; -} - -typedef enum : uint32_t { - APPMANAGER_L2TEST_STATE_INVALID = 0x00000000, - APPMANAGER_L2TEST_ONAPPINSTALLED = 0x00000001, - APPMANAGER_L2TEST_ONAPPUNINSTALLED = 0x00000002, - APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED = 0x00000003, - APPMANAGER_L2TEST_ONAPPLAUNCHREQUEST = 0x00000004, - APPMANAGER_L2TEST_ONAPPUNLOADED = 0x00000005 -}Appmanager_L2test_Event; - -class AsyncHandlerMock_AppManager -{ - public: - AsyncHandlerMock_AppManager() - { - } - MOCK_METHOD(void, onAppInstalled, (const string& appId, const string& version)); - MOCK_METHOD(void, onAppUninstalled, (const string& appId)); - MOCK_METHOD(void, onAppLifecycleStateChanged, (const string& appId, const string& appInstanceId,const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason)); - MOCK_METHOD(void, onAppLaunchRequest, (const string& appId, const string& intent, const string& source)); - MOCK_METHOD(void, onAppUnloaded, (const string& appId, const string& appInstanceId)); -}; - -class AppManagerTest : public L2TestMocks { -protected: - virtual ~AppManagerTest() override; - - public: - AppManagerTest(); - - void onAppInstalled(const string& appId, const string& version); - void onAppUninstalled(const string& appId); - void onAppLifecycleStateChanged(const string& appId, const string& appInstanceId,const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason); - void onAppLaunchRequest(const string& appId, const string& intent, const string& source); - void onAppUnloaded(const string& appId, const string& appInstanceId); - - uint32_t WaitForRequestStatus(uint32_t timeOutMs,Appmanager_L2test_Event expectedStatus); - uint32_t CreateAppManagerInterfaceObjectUsingComRPCConnection(); - - private: - /** @brief Mutex */ - std::mutex mMutex; - - /** @brief Condition variable */ - std::condition_variable mConditionVariable; - - /** @brief Event signalled flag */ - uint32_t mEventSignalled; - - protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *mControllerAppmanager; - - /** @brief Pointer to the IAppManager interface */ - Exchange::IAppManager *mAppmanagerPlugin; -}; - -AppManagerTest:: AppManagerTest():L2TestMocks() -{ - Core::JSONRPC::Message message; - string response; - uint32_t status = Core::ERROR_GENERAL; - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = ActivateService("org.rdk.LifeCycleManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = ActivateService("org.rdk.AppManager"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/** - * @brief Destructor for SystemServices L2 test class - */ -AppManagerTest::~AppManagerTest() -{ - uint32_t status = Core::ERROR_GENERAL; - - ON_CALL(*p_rBusApiImplMock, rbus_close(::testing::_ )) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - status = DeactivateService("org.rdk.AppManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.LifeCycleManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -uint32_t AppManagerTest::WaitForRequestStatus(uint32_t timeOutMs, Appmanager_L2test_Event expectedStatus) -{ - std::unique_lock lock(mMutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeOutMs); - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - - while (!(expectedStatus & mEventSignalled)) - { - if (mConditionVariable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = mEventSignalled; - return signalled; -} - -uint32_t AppManagerTest::CreateAppManagerInterfaceObjectUsingComRPCConnection() -{ - uint32_t returnValue = Core::ERROR_GENERAL; - Core::ProxyType> appManagerEngine; - Core::ProxyType appManagerClient; - - TEST_LOG("Creating appManagerEngine"); - appManagerEngine = Core::ProxyType>::Create(); - appManagerClient = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(appManagerEngine)); - - TEST_LOG("Creating appManagerEngine Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - appManagerEngine->Announcements(mappManagerClient->Announcement()); -#endif - if (!appManagerClient.IsValid()) - { - TEST_LOG("Invalid appManagerClient"); - } - else - { - mControllerAppmanager = appManagerClient->Open(_T("org.rdk.AppManager"), ~0, 3000); - if (mControllerAppmanager) - { - mAppmanagerPlugin = mControllerAppmanager->QueryInterface(); - returnValue = Core::ERROR_NONE; - } - } - return returnValue; -} - -void AppManagerTest::onAppInstalled(const string& appId, const string& version) -{ - TEST_LOG("onAppInstalled event triggered ***\n"); - std::unique_lock lock(mMutex); - - TEST_LOG("onAppInstalled received appId: %s version: %s\n", appId.c_str(), version.c_str()); - - /* Notify the requester thread. */ - mEventSignalled |= APPMANAGER_L2TEST_ONAPPINSTALLED; - mConditionVariable.notify_one(); -} - -void AppManagerTest::onAppUninstalled(const string& appId) -{ - TEST_LOG("onAppUninstalled event triggered ***\n"); - std::unique_lock lock(mMutex); - - TEST_LOG("onAppUninstalled received appId: %s \n", appId.c_str()); - - /* Notify the requester thread. */ - mEventSignalled |= APPMANAGER_L2TEST_ONAPPUNINSTALLED; - mConditionVariable.notify_one(); -} - -void AppManagerTest::onAppLifecycleStateChanged(const string& appId, const string& appInstanceId,const Exchange::IAppManager::AppLifecycleState newState, const Exchange::IAppManager::AppLifecycleState oldState, const Exchange::IAppManager::AppErrorReason errorReason) -{ - TEST_LOG("OnAppLifecycleStateChanged event triggered ***\n"); - std::unique_lock lock(mMutex); - - TEST_LOG("OnAppLifecycleStateChanged received appId: %s appInstanceId: %s newState: %u oldState: %u errorReason: %u\n", - appId.c_str(), - appInstanceId.c_str(), - newState, - oldState, - errorReason); - - /* Notify the requester thread. */ - mEventSignalled |= APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED; - mConditionVariable.notify_one(); -} - -void AppManagerTest::onAppLaunchRequest(const string& appId, const string& intent, const string& source) -{ - TEST_LOG("onAppLaunchRequest event triggered ***\n"); - std::unique_lock lock(mMutex); - - TEST_LOG("onAppLaunchRequest received appId: %s intent: %s source: %s\n", appId.c_str(), intent.c_str(), source.c_str()); - - /* Notify the requester thread. */ - mEventSignalled |= APPMANAGER_L2TEST_ONAPPLAUNCHREQUEST; - mConditionVariable.notify_one(); -} - -void AppManagerTest::onAppUnloaded(const string& appId, const string& appInstanceId) -{ - TEST_LOG("OnAppUnloaded event triggered ***\n"); - std::unique_lock lock(mMutex); - - TEST_LOG("OnAppUnloaded received appId: %s appInstanceId: %s\n", appId.c_str(), appInstanceId.c_str()); - - /* Notify the requester thread. */ - mEventSignalled |= APPMANAGER_L2TEST_ONAPPUNLOADED; - mConditionVariable.notify_one(); -} - -/* Begin: Test cases using JSON-RPC */ - -/******************************************************** -************Test case Details ************************** -** 1. Test SetAppProperty and GetAppProperty success scenario -** 2. Call SetAppProperty method using json-rpc with passing valid arguments and expected sucess -** 3. Call GetAppProperty method using json-rpc with passing valid arguments and expected sucess -** 4. Compare the value with expected value -*******************************************************/ -TEST_F(AppManagerTest, SetAndGetAppPropertySuccessCaseUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - Core::JSON::String resultString; - std::string propValue = ""; - string appId = "com.example.myapp"; - string key = "delay"; - string value = "\"10\""; - - TEST_LOG("Testing SetAppPropertyJsonRpcConnectionSuccessCase "); - - JsonObject params; - params["appId"] = appId; - params["key"] = key; - params["value"] = value; - /* Invoking setAppProperty method */ - status = InvokeServiceMethod("org.rdk.AppManager", "setAppProperty", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Invoking getAppProperty method */ - JsonObject params1; - params1["appId"] = appId; - params1["key"] = key; - status = InvokeServiceMethod("org.rdk.AppManager", "getAppProperty", params1, resultString); - EXPECT_EQ(status,Core::ERROR_NONE); - - propValue = resultString.Value(); - TEST_LOG("propValue: %s expected value: %s", propValue.c_str(), value.c_str()); - EXPECT_EQ(propValue, value); - EXPECT_TRUE(propValue == value); -} - -/******************************************************** -************Test case Details ************************** -** 1. Test SetAppProperty and GetAppProperty Failure scenario -** 2. Call SetAppProperty method using json-rpc with passing Empty AppId and expected core::ERROR_GENERAL -** 3. Call GetAppProperty method using json-rpc with passing Empty AppId and expected core::ERROR_GENERAL -*******************************************************/ -TEST_F(AppManagerTest, SetAndGetAppPropertyEmptyAppIdUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - Core::JSON::String resultString; - std::string propValue = ""; - string appId = ""; - string key = "delay"; - string value = "\"10\""; - - TEST_LOG("Testing SetAndGetAppPropertyEmptyAppIdUsingJsonRpc "); - - /* Invoking setAppProperty method */ - JsonObject params; - params["appId"] = appId; - params["key"] = key; - params["value"] = value; - status = InvokeServiceMethod("org.rdk.AppManager", "setAppProperty", params, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - - /* Invoking getAppProperty method */ - JsonObject params1; - params1["appId"] = appId; - params1["key"] = key; - status = InvokeServiceMethod("org.rdk.AppManager", "getAppProperty", params1, resultString); - EXPECT_EQ(status,Core::ERROR_GENERAL); -} - -/******************************************************** -************Test case Details ************************** -** 1. Test SetAppProperty and GetAppProperty Failure scenario -** 2. Call SetAppProperty method using json-rpc with passing Empty key and expected core::ERROR_GENERAL -** 3. Call GetAppProperty method using json-rpc with passing Empty key and expected core::ERROR_GENERAL -*******************************************************/ -TEST_F(AppManagerTest, SetAndGetAppPropertyEmptyKeyUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - Core::JSON::String resultString; - std::string propValue = ""; - string appId = "com.example.myapp"; - string key = ""; - string value = "\"10\""; - - TEST_LOG("Testing SetAndGetAppPropertyEmptyKeyUsingJsonRpc"); - - /* Invoking setAppProperty method */ - JsonObject params; - params["appId"] = appId; - params["key"] = key; - params["value"] = value; - status = InvokeServiceMethod("org.rdk.AppManager", "setAppProperty", params, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - - /* Invoking getAppProperty method */ - JsonObject params1; - params1["appId"] = appId; - params1["key"] = key; - status = InvokeServiceMethod("org.rdk.AppManager", "getAppProperty", params1, resultString); - EXPECT_EQ(status,Core::ERROR_GENERAL); -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Launch, Close App mehods sequence -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing valid arguments and expected success -** 6. Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7. Call closeApp method using json-rpc with passing valid arguments and expected success -** 8. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 9. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, PreLoadLaunchAndCloseAppSuccessCaseUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing PreLoadLaunchAndCloseAppSuccessCaseUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling LaunchApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject params; - params["appId"] = "com.example.myapp"; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling CloseApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject closeParams; - closeParams["appId"] = "com.example.myapp"; - status = InvokeServiceMethod("org.rdk.AppManager", "closeApp", closeParams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Close and Terminate App mehods sequence -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 6 Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7 Call terminateApp method using json-rpc with passing valid arguments and expected success -** 8 Waiting for the onAppLifecycleStateChanged event to receive with Terminated state -** 9 UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, PreLoadAndTerminateAppSuccessCaseUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing PreLoadAndTerminateAppSuccessCaseUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling LaunchApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject params; - params["appId"] = "com.example.myapp"; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling CloseApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject closeParams; - closeParams["appId"] = "com.example.myapp"; - status = InvokeServiceMethod("org.rdk.AppManager", "closeApp", closeParams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling TerminateApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_TERMINATED; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject terminateParams; - terminateParams["appId"] = "com.example.myapp"; - status = InvokeServiceMethod("org.rdk.AppManager", "terminateApp", terminateParams, resultJson); -#ifdef ENABLE_LIFECYCLE_STATE_CHANGE_VERIFICATION - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_LIFECYCLE_STATE_CHANGE_VERIFICATION */ - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoadApp method with empty AppId -** 1. Call preloadApp method using json-rpc with passing Empty AppId and expected failiure -*******************************************************/ -TEST_F(AppManagerTest, PreLoadAppEmptyAppIdUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing PreLoadAppEmptyAppIdUsingJsonRpc "); - - /* Calling PreloadApp */ - JsonObject preLoadparams; - preLoadparams["appId"] = ""; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); -} - -/******************************************************** -************Test case Details ************************** -** Verify LaunchApp method with empty AppId -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing Empty AppId and expected failiure -** 6. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, LaunchAppEmptyAppIdUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing LaunchAppEmptyAppIdUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling LaunchApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject params; - params["appId"] = ""; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_INVALID_PARAMETER); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify Close App with empty AppId -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing valid arguments and expected success -** 6. Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7. Call closeApp method using json-rpc with passing Empty AppId and expected failiure -** 8. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, CloseAppEmptyAppIdUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing CloseAppEmptyAppIdUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling LaunchApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject params; - params["appId"] = "com.example.myapp"; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling CloseApp */ - JsonObject closeParams; - closeParams["appId"] = ""; - status = InvokeServiceMethod("org.rdk.AppManager", "closeApp", closeParams, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify TerminateApp with empty AppId -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing valid arguments and expected success -** 6. Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7. Call closeApp method using json-rpc with passing valid arguments and expected success -** 8. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 9. Call terminateApp method using json-rpc with passing Empty AppId and expected failiure -** 10. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, TerminateAppEmptyAppIdUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing TerminateAppEmptyAppIdUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling TerminateApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_TERMINATED; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject terminateParams; - terminateParams["appId"] = ""; - status = InvokeServiceMethod("org.rdk.AppManager", "terminateApp", terminateParams, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Launch, Close mehods sequence -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing valid arguments and expected success -** 6. Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7. Call closeApp method using json-rpc with passing valid arguments and expected success -** 8. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 9. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, PreLoadLaunchAppSuccessCaseUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - - TEST_LOG("Testing PreLoadLaunchAppSuccessCaseUsingJsonRpc "); - - /* Calling PreloadApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Calling LaunchApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject params; - params["appId"] = "com.example.myapp"; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling CloseApp */ -#ifdef ENABLE_NOTIFICATION_VERIFICATION - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - JsonObject closeParams; - closeParams["appId"] = "com.example.myapp"; - status = InvokeServiceMethod("org.rdk.AppManager", "closeApp", closeParams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Launch Apps methods and call GetLoadedApps method sequence -** 1. Subscribe the onAppLifecycleStateChanged event -** 2. Setting mock values for the onAppLifecycleStateChanged -** 3. Call preloadApp method using json-rpc with passing valid arguments and expected success -** 4. Waiting for the onAppLifecycleStateChanged event to receive with Running state -** 5. Call launchApp method using json-rpc with passing valid arguments and expected success -** 6. Waiting for the onAppLifecycleStateChanged event to receive with Active state -** 7. Call GetLoadedApps method using json-rpc and expected success and get the loaded Apps -** 9. UnSubscribe the onAppLifecycleStateChanged event -*******************************************************/ -TEST_F(AppManagerTest, GetLoadedAppsSuccessCaseUsingJsonRpc) -{ - JSONRPC::LinkType jsonrpc(APPMANAGER_CALLSIGN, APPMANAGERL2TEST_CALLSIGN); - StrictMock asyncHandler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - Core::JSON::String resultString; - string apps = ""; - string expectedApps = "\"[{\\\"appId\\\":\\\"com.example.myapp\\\",\\\"type\\\":\\\"INTERACTIVE_APP\\\",\\\"lifecycleState\\\":0,\\\"targetLifecycleState\\\":2,\\\"activeSessionId\\\":\\\"\\\",\\\"appInstanceId\\\":\\\"\\\"}]\""; - - TEST_LOG("Testing GetLoadedAppsSuccessCaseUsingJsonRpc "); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - uint32_t signalled = APPMANAGER_L2TEST_STATE_INVALID; - string expectedAppId = "com.example.myapp"; - string expectedAppInstanceId = "1"; - Exchange::IAppManager::AppLifecycleState expectedNewState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - Exchange::IAppManager::AppLifecycleState expectedOldState = IAppManager::AppLifecycleState::APP_STATE_UNKNOWN; - Exchange::IAppManager::AppErrorReason expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - /* Subscribe onAppLifecycleStateChanged */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onAppLifecycleStateChanged"), - [this, &asyncHandler](const JsonObject& parameters) { - string appId = parameters["appId"].String(); - string appInstanceId = parameters["appInstanceId"].String(); - Exchange::IAppManager::AppLifecycleState newState = static_cast(parameters["newState"].Number()); - Exchange::IAppManager::AppLifecycleState oldState = static_cast(parameters["oldState"].Number()); - Exchange::IAppManager::AppErrorReason errorReason = static_cast(parameters["errorReason"].Number()); - asyncHandler.onAppLifecycleStateChanged(appId, appInstanceId, newState, oldState, errorReason); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling PreloadApp with appId: com.example.myapp*/ - JsonObject preLoadparams; - preLoadparams["appId"] = "com.example.myapp"; - preLoadparams["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "preloadApp", preLoadparams, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - - expectedNewState = IAppManager::AppLifecycleState::APP_STATE_ACTIVE; - expectedOldState = IAppManager::AppLifecycleState::APP_STATE_RUNNING; - expectedErrorReason = IAppManager::AppErrorReason::APP_ERROR_UNKNOWN; - - EXPECT_CALL(asyncHandler, onAppLifecycleStateChanged(MatchRequestStatusString(expectedAppId), - MatchRequestStatusString(expectedAppInstanceId), - MatchRequestStatusNumber(expectedNewState), - MatchRequestStatusNumber(expectedOldState), - MatchRequestStatusNumber(expectedErrorReason))) - .WillOnce(Invoke(this, &AppManagerTest::onAppLifecycleStateChanged)); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - /* Calling LaunchApp */ - JsonObject params; - params["appId"] = "com.example.myapp"; - params["intent"] = "start"; - params["launchArgs"] = "{\"key1\":\"38\"}"; - status = InvokeServiceMethod("org.rdk.AppManager", "launchApp", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - signalled = WaitForRequestStatus(JSON_TIMEOUT,APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); - EXPECT_TRUE(signalled & APPMANAGER_L2TEST_ONAPPLIFECYCLESTATECHANGED); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ - - //JsonObject params1; - ///* Calling GetLoadedApps */ - //status = InvokeServiceMethod("org.rdk.AppManager", "getLoadedApps", params1, resultString); - //EXPECT_EQ(status,Core::ERROR_NONE); - - //resultString.ToString(apps); - //TEST_LOG("apps: %s", apps.c_str()); - //EXPECT_EQ(apps, expectedApps); - //EXPECT_TRUE(apps == expectedApps); - -#ifdef ENABLE_NOTIFICATION_VERIFICATION - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onAppLifecycleStateChanged")); - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_NOTIFICATION_VERIFICATION */ -} -/* End: Test cases using JSON-RPC */ - -/* Begin: Test cases using COM-RPC */ - -/******************************************************** -************Test case Details ************************** -** Verify Set and Get App property methods -** 1. Create COM-RPC connection -** 3. Call setAppProperty method with passing valid arguments and expected sucess -** 3. Call getAppProperty method with passing valid arguments and expected sucess -** 4. Compare with result value with expected value -** 5. Release interface object and COM-RPC connection -*******************************************************/ -TEST_F(AppManagerTest, SetAndGetAppPropertyComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - - if (CreateAppManagerInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid appManagerClient"); - } - else - { - ASSERT_TRUE(mControllerAppmanager!= nullptr); - if (mControllerAppmanager) - { - ASSERT_TRUE(mAppmanagerPlugin!= nullptr); - if (mAppmanagerPlugin) - { - mAppmanagerPlugin->AddRef(); - - string appId = "com.example.myapp"; - string key = "delay"; - string value = "\"10\""; /* string as json string format */ - string expectedValue = "\"10\""; - - TEST_LOG("Calling SetAppProperty"); - status = mAppmanagerPlugin->SetAppProperty(appId, key, value); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - TEST_LOG("Calling GetAppProperty"); - value = ""; - status = mAppmanagerPlugin->GetAppProperty(appId, key, value); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - TEST_LOG("value: %s expectedValue:%s", value.c_str(), expectedValue.c_str()); - - EXPECT_EQ(value, expectedValue); - - mAppmanagerPlugin->Release(); - } - else - { - TEST_LOG("mAppmanagerPlugin is NULL"); - } - mControllerAppmanager->Release(); - } - else - { - TEST_LOG("mControllerAppmanager is NULL"); - } - } -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Launch, Close and Termaite App mehods sequence -** 1. Create COM-RPC connection -** 2. Call preloadApp method passing valid arguments and expect sucess -** 3. Call launchApp method passing valid arguments and expect sucess -** 4. Call closeApp method passing valid arguments and expect sucess -** 5. Call terminateApp method passing valid arguments and expect sucess -** 6. Release interface object and COM-RPC connection -*******************************************************/ -TEST_F(AppManagerTest, PreLoadLaunchCloseAndTerminateAppComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - - if (CreateAppManagerInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid appManagerClient"); - } - else - { - ASSERT_TRUE(mControllerAppmanager!= nullptr); - if (mControllerAppmanager) - { - ASSERT_TRUE(mAppmanagerPlugin!= nullptr); - if (mAppmanagerPlugin) - { - mAppmanagerPlugin->AddRef(); - - string appId = "com.example.myapp"; - string launchArgs = "{\"key1\":\"38\"}"; - string error = ""; - string value = "\"10\""; /* string as json string format */ - string expectedValue = "\"10\""; - - TEST_LOG("Calling PreloadApp"); - status = mAppmanagerPlugin->PreloadApp(appId, launchArgs, error); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - string intent = "start"; - TEST_LOG("Calling LaunchApp"); - value = ""; - status = mAppmanagerPlugin->LaunchApp(appId, intent, launchArgs); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - //TEST_LOG("Calling GetLoadedApps"); - //string appData = ""; - //string expectedApps = "[{\"appId\":\"com.example.myapp\",\"type\":1,\"lifecycleState\":0,\"targetLifecycleState\":2,\"activeSessionId\":\"\",\"appInstanceId\":\"\"}]"; - //status = mAppmanagerPlugin->GetLoadedApps(appData); - //EXPECT_EQ(status,Core::ERROR_NONE); - //if (status != Core::ERROR_NONE) - //{ - // std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - // TEST_LOG("Err: %s", errorMsg.c_str()); - //} - - //TEST_LOG("appData: %s expectedApps:%s", appData.c_str(), expectedApps.c_str()); - - //EXPECT_EQ(appData, expectedApps); - - TEST_LOG("Calling CloseApp"); - value = ""; - status = mAppmanagerPlugin->CloseApp(appId); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - TEST_LOG("Calling TerminateApp"); - value = ""; - status = mAppmanagerPlugin->TerminateApp(appId); -#ifdef ENABLE_LIFECYCLE_STATE_CHANGE_VERIFICATION - EXPECT_EQ(status,Core::ERROR_NONE); -#endif /* ENABLE_LIFECYCLE_STATE_CHANGE_VERIFICATION */ - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - mAppmanagerPlugin->Release(); - } - else - { - TEST_LOG("mAppmanagerPlugin is NULL"); - } - mControllerAppmanager->Release(); - } - else - { - TEST_LOG("mControllerAppmanager is NULL"); - } - } -} - -/******************************************************** -************Test case Details ************************** -** Verify PreLoad, Launch, Close App mehods sequence -** 1. Create COM-RPC connection -** 3. Call preloadApp method passing valid arguments and expect sucess -** 3. Call launchApp method passing valid arguments and expect sucess -** 4. Call GetLoadedApps method and expect success along with app data -** 5. Call closeApp method passing valid arguments and expect sucess -** 6. Call GetLoadedApps method and expect success along with empty app data -** 7. Release interface object and COM-RPC connection -*******************************************************/ -TEST_F(AppManagerTest, PreLoadLaunchCloseAppComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - - if (CreateAppManagerInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid appManagerClient"); - } - else - { - ASSERT_TRUE(mControllerAppmanager!= nullptr); - if (mControllerAppmanager) - { - ASSERT_TRUE(mAppmanagerPlugin!= nullptr); - if (mAppmanagerPlugin) - { - mAppmanagerPlugin->AddRef(); - - string appId = "com.example.myapp"; - string launchArgs = "{\"key1\":\"38\"}"; - string error = ""; - string value = "\"10\""; /* string as json string format */ - string expectedValue = "\"10\""; - - TEST_LOG("Calling PreloadApp"); - status = mAppmanagerPlugin->PreloadApp(appId, launchArgs, error); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - string intent = "start"; - TEST_LOG("Calling LaunchApp"); - value = ""; - status = mAppmanagerPlugin->LaunchApp(appId, intent, launchArgs); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - //TEST_LOG("Calling GetLoadedApps"); - //string appDataAfterLaunch = ""; - //string expectedAppData = "[{\"appId\":\"com.example.myapp\",\"type\":1,\"lifecycleState\":0,\"targetLifecycleState\":2,\"activeSessionId\":\"\",\"appInstanceId\":\"\"}]"; - //status = mAppmanagerPlugin->GetLoadedApps(appDataAfterLaunch); - //EXPECT_EQ(status,Core::ERROR_NONE); - //if (status != Core::ERROR_NONE) - //{ - // std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - // TEST_LOG("Err: %s", errorMsg.c_str()); - //} - - //TEST_LOG("appDataAfterLaunch: %s expectedAppData:%s", appDataAfterLaunch.c_str(), expectedAppData.c_str()); - - //EXPECT_EQ(appDataAfterLaunch, expectedAppData); - - TEST_LOG("Calling CloseApp"); - value = ""; - status = mAppmanagerPlugin->CloseApp(appId); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - //TEST_LOG("Calling GetLoadedApps"); - //string appDataAfterClose = ""; - //string expectedAppDataAfterClose = "[{\"appId\":\"com.example.myapp\",\"type\":1,\"lifecycleState\":0,\"targetLifecycleState\":3,\"activeSessionId\":\"\",\"appInstanceId\":\"\"}]"; - //status = mAppmanagerPlugin->GetLoadedApps(appDataAfterClose); - //EXPECT_EQ(status,Core::ERROR_NONE); - //if (status != Core::ERROR_NONE) - //{ - // std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - // TEST_LOG("Err: %s", errorMsg.c_str()); - //} - - //TEST_LOG("appDataAfterClose: %s expectedAppDataAfterClose:%s", appDataAfterClose.c_str(), expectedAppDataAfterClose.c_str()); - - //EXPECT_EQ(appDataAfterClose, expectedAppDataAfterClose); - - mAppmanagerPlugin->Release(); - } - else - { - TEST_LOG("mAppmanagerPlugin is NULL"); - } - mControllerAppmanager->Release(); - } - else - { - TEST_LOG("mControllerAppmanager is NULL"); - } - } -} - -/* End: Test cases using COM-RPC */ - - diff --git a/Tests/L2Tests/tests/Migration_L2Test.cpp b/Tests/L2Tests/tests/Migration_L2Test.cpp deleted file mode 100644 index 4c6acb4..0000000 --- a/Tests/L2Tests/tests/Migration_L2Test.cpp +++ /dev/null @@ -1,1179 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include -#include -#include - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -#define JSON_TIMEOUT (1000) -#define MIGRATION_CALLSIGN _T("org.rdk.Migration") -#define MIGRATION_L2TEST_CALLSIGN _T("L2tests.1") - -// Sleep duration constants for test cleanup and synchronization (in microseconds) -#define CLEANUP_DELAY_MICROSECONDS 500000 // 500ms - Cleanup delay after releasing interfaces - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::IMigration; - -/** - * @brief Migration L2 test class declaration - */ -class MigrationL2Test : public L2TestMocks { -protected: - MigrationL2Test(); - virtual ~MigrationL2Test() override; - -public: - uint32_t CreateMigrationInterfaceObjectUsingComRPCConnection(); - -protected: - /** @brief ProxyType objects for proper cleanup */ - Core::ProxyType> mMigrationEngine; - Core::ProxyType mMigrationClient; - - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *mControllerMigration; - - /** @brief Pointer to the IMigration interface */ - Exchange::IMigration *mMigrationPlugin; -}; - -/** - * @brief Constructor for Migration L2 test class - */ -MigrationL2Test::MigrationL2Test() : L2TestMocks() -{ - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Migration L2 test constructor"); - - /* Try to activate Migration plugin - if it fails, tests will be skipped */ - status = ActivateService("org.rdk.Migration"); - if (status != Core::ERROR_NONE) { - TEST_LOG("Migration service activation failed with error: %d", status); - // Don't fail here - individual tests will check and skip if needed - } else { - TEST_LOG("Migration service activated successfully"); - } -} - -/** - * @brief Destructor for Migration L2 test class - */ -MigrationL2Test::~MigrationL2Test() -{ - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Migration L2 test destructor"); - - // Clean up interface objects - if (mMigrationPlugin != nullptr) { - mMigrationPlugin->Release(); - mMigrationPlugin = nullptr; - } - - if (mControllerMigration != nullptr) { - mControllerMigration->Release(); - mControllerMigration = nullptr; - } - - usleep(CLEANUP_DELAY_MICROSECONDS); - - // Try to deactivate service - may fail if activation failed - status = DeactivateService("org.rdk.Migration"); - if (status != Core::ERROR_NONE) { - TEST_LOG("Migration service deactivation failed with error: %d", status); - } else { - TEST_LOG("Migration service deactivated successfully"); - } -} - -/** - * @brief Creates Migration interface object using COM-RPC connection - * @return Core::ERROR_NONE on success, error code otherwise - */ -uint32_t MigrationL2Test::CreateMigrationInterfaceObjectUsingComRPCConnection() -{ - uint32_t returnValue = Core::ERROR_GENERAL; - - TEST_LOG("Creating Migration COM-RPC connection"); - - // Create the migration engine - mMigrationEngine = Core::ProxyType>::Create(); - mMigrationClient = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(mMigrationEngine)); - - if (!mMigrationClient.IsValid()) { - TEST_LOG("Invalid migrationClient"); - } - else - { - mControllerMigration = mMigrationClient->Open(_T("org.rdk.Migration"), ~0, 3000); - if (mControllerMigration) - { - mMigrationPlugin = mControllerMigration->QueryInterface(); - returnValue = Core::ERROR_NONE; - } - } - return returnValue; -} - -/** - * @brief Parameterized test class for GetBootTypeInfo with different boot types - */ -class GetBootTypeInfoTest : public MigrationL2Test, public ::testing::WithParamInterface> {}; - -/** - * @brief Parameterized test for GetBootTypeInfo with different boot type values - * @details Tests GetBootTypeInfo when boot type file contains different valid boot types - * and validates the exact expected enum value is returned - */ -TEST_P(GetBootTypeInfoTest, GetBootTypeInfo_BootTypes) -{ - // Create bootType file with parameterized content - const std::string bootTypeFile = "/tmp/bootType"; - const char* bootTypeString = GetParam().first; - Exchange::IMigration::BootType expectedBootType = GetParam().second; - const std::string bootTypeContent = std::string("BOOT_TYPE=") + bootTypeString + "\n"; - - std::ofstream file(bootTypeFile); - if (file.is_open()) { - file << bootTypeContent; - file.close(); - TEST_LOG("Created bootType file with %s content", bootTypeString); - } else { - FAIL() << "Could not create bootType file for test"; - } - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::BootTypeInfo bootTypeInfo; - Core::hresult result = mMigrationPlugin->GetBootTypeInfo(bootTypeInfo); - - ASSERT_EQ(result, Core::ERROR_NONE) << "GetBootTypeInfo failed for " << bootTypeString; - - // Validate the exact expected boot type value - EXPECT_EQ(bootTypeInfo.bootType, expectedBootType) - << "Boot type mismatch for " << bootTypeString - << " - Expected: " << static_cast(expectedBootType) - << ", Got: " << static_cast(bootTypeInfo.bootType); - - TEST_LOG("GetBootTypeInfo %s test PASSED - Expected and got boot type: %d", - bootTypeString, static_cast(expectedBootType)); - - // Clean up test file - std::remove(bootTypeFile.c_str()); -} - -INSTANTIATE_TEST_SUITE_P( - BootTypeTests, - GetBootTypeInfoTest, - ::testing::Values( - std::make_pair("BOOT_INIT", Exchange::IMigration::BootType::BOOT_TYPE_INIT), - std::make_pair("BOOT_NORMAL", Exchange::IMigration::BootType::BOOT_TYPE_NORMAL), - std::make_pair("BOOT_MIGRATION", Exchange::IMigration::BootType::BOOT_TYPE_MIGRATION), - std::make_pair("BOOT_UPDATE", Exchange::IMigration::BootType::BOOT_TYPE_UPDATE) - ) -); - -/**************************************************/ -// Test Cases -/**************************************************/ - -/** - * @brief Test Migration GetBootTypeInfo API - Normal operation - * @details Verifies that GetBootTypeInfo method returns the exact expected boot type for BOOT_NORMAL - */ -TEST_F(MigrationL2Test, GetBootTypeInfo_Normal) -{ - const std::string bootTypeFile = "/tmp/bootType"; - const std::string bootTypeContent = "BOOT_TYPE=BOOT_NORMAL\n"; - - std::ofstream file(bootTypeFile); - ASSERT_TRUE(file.is_open()) << "Could not create bootType file for test"; - file << bootTypeContent; - file.close(); - TEST_LOG("Created boot type file: %s", bootTypeFile.c_str()); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::BootTypeInfo bootTypeInfo; - Core::hresult result = mMigrationPlugin->GetBootTypeInfo(bootTypeInfo); - - ASSERT_EQ(result, Core::ERROR_NONE) << "GetBootTypeInfo failed"; - - // Validate the exact expected boot type value - EXPECT_EQ(bootTypeInfo.bootType, Exchange::IMigration::BootType::BOOT_TYPE_NORMAL) - << "Expected BOOT_TYPE_NORMAL (" << static_cast(Exchange::IMigration::BootType::BOOT_TYPE_NORMAL) - << "), but got: " << static_cast(bootTypeInfo.bootType); - - TEST_LOG("GetBootTypeInfo test PASSED - Expected and got BOOT_TYPE_NORMAL (%d)", - static_cast(Exchange::IMigration::BootType::BOOT_TYPE_NORMAL)); - - // Clean up test file - ASSERT_EQ(std::remove(bootTypeFile.c_str()), 0) << "Failed to remove test boot type file"; - TEST_LOG("Removed test boot type file"); -} - -/** - * @brief Test Migration GetMigrationStatus API - Normal operation - * @details Verifies that GetMigrationStatus method returns the exact expected migration status - */ -TEST_F(MigrationL2Test, GetMigrationStatus_Normal) -{ - // Setup RFC mock for GetMigrationStatus to return specific expected value - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "NOT_STARTED"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult result = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - ASSERT_EQ(result, Core::ERROR_NONE) << "GetMigrationStatus failed"; - - // Validate the exact expected migration status value - EXPECT_EQ(migrationStatusInfo.migrationStatus, Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED) - << "Expected MIGRATION_STATUS_NOT_STARTED (" << static_cast(Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED) - << "), but got: " << static_cast(migrationStatusInfo.migrationStatus); - - TEST_LOG("GetMigrationStatus test PASSED - Expected and got MIGRATION_STATUS_NOT_STARTED (%d)", - static_cast(Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED)); -} - -/** - * @brief Test Migration SetMigrationStatus API - Normal operation - * @details Verifies that SetMigrationStatus method properly sets migration status - * and validates both the success result and the actual status value - */ -TEST_F(MigrationL2Test, SetMigrationStatus_Normal) -{ - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Test setting to STARTED status - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus( - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED, migrationResult); - - ASSERT_EQ(setResult, Core::ERROR_NONE) << "SetMigrationStatus failed"; - ASSERT_TRUE(migrationResult.success) << "SetMigrationStatus result indicates failure"; - - // Setup RFC mock for GetMigrationStatus verification call to return exactly what we set - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "STARTED"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - // Verify the status was set correctly by reading it back - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - ASSERT_EQ(getResult, Core::ERROR_NONE) << "GetMigrationStatus failed after successful set"; - EXPECT_EQ(migrationStatusInfo.migrationStatus, Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED) - << "Migration status was not set correctly - Expected STARTED (" - << static_cast(Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED) - << "), Got: " << static_cast(migrationStatusInfo.migrationStatus); - - TEST_LOG("SetMigrationStatus test PASSED - Status set to STARTED and verified correctly"); -} - -/** - * @brief Test Migration SetMigrationStatus API - Set to MIGRATION_COMPLETED - * @details Verifies that SetMigrationStatus can set status to MIGRATION_COMPLETED - * and validates the exact expected value is stored and retrieved - */ -TEST_F(MigrationL2Test, SetMigrationStatus_ToCompleted) -{ - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Test setting to MIGRATION_COMPLETED status - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus( - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED, migrationResult); - - ASSERT_EQ(setResult, Core::ERROR_NONE) << "SetMigrationStatus to COMPLETED failed"; - ASSERT_TRUE(migrationResult.success) << "SetMigrationStatus result indicates failure"; - - // Setup RFC mock for GetMigrationStatus verification call to return exactly what we set - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "MIGRATION_COMPLETED"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - // Verify the status was set correctly - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - ASSERT_EQ(getResult, Core::ERROR_NONE) << "GetMigrationStatus failed after successful set"; - EXPECT_EQ(migrationStatusInfo.migrationStatus, Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED) - << "Migration status was not set to MIGRATION_COMPLETED correctly - Expected (" - << static_cast(Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED) - << "), Got: " << static_cast(migrationStatusInfo.migrationStatus); - - TEST_LOG("SetMigrationStatus test PASSED - Status set to MIGRATION_COMPLETED and verified correctly"); -} - -/** - * @brief Test Migration API sequence - Set multiple statuses in sequence - * @details Verifies that migration status can be updated through different stages - */ -TEST_F(MigrationL2Test, SetMigrationStatus_Sequence) -{ - // Setup RFC mock to read from the file that SetMigrationStatus writes to - // Since SetMigrationStatus writes to file and GetMigrationStatus reads from RFC, - // we need to mock the RFC to return whatever was last written - std::string lastWrittenStatus = "NOT_STARTED"; - - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillRepeatedly(testing::Invoke( - [&lastWrittenStatus](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, lastWrittenStatus.c_str()); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Map of status enum to string for updating the mock - static const std::unordered_map statusToString = { - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED, "NOT_STARTED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED, "STARTED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED, "PRIORITY_SETTINGS_MIGRATED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED, "DEVICE_SETTINGS_MIGRATED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_CLOUD_SETTINGS_MIGRATED, "CLOUD_SETTINGS_MIGRATED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_APP_DATA_MIGRATED, "APP_DATA_MIGRATED" }, - { Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED, "MIGRATION_COMPLETED" } - }; - - // Test sequence of migration status updates - std::vector testSequence = { - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_CLOUD_SETTINGS_MIGRATED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_APP_DATA_MIGRATED, - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED - }; - - for (auto testStatus : testSequence) { - // Update the mock to return the status we're about to set - auto it = statusToString.find(testStatus); - if (it != statusToString.end()) { - lastWrittenStatus = it->second; - } - - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus(testStatus, migrationResult); - - // Handle both success and error cases gracefully - if (setResult == Core::ERROR_NONE) { - EXPECT_TRUE(migrationResult.success) - << "SetMigrationStatus result indicates failure for status: " << static_cast(testStatus); - - // Verify the status was set correctly - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - if (getResult == Core::ERROR_NONE) { - EXPECT_EQ(migrationStatusInfo.migrationStatus, testStatus) - << "Migration status verification failed for status: " << static_cast(testStatus); - TEST_LOG("Migration status sequence step passed - Status: %d (verified)", static_cast(testStatus)); - } else { - TEST_LOG("SetMigrationStatus succeeded for status %d but GetMigrationStatus failed with error: %d", - static_cast(testStatus), getResult); - TEST_LOG("Migration status sequence step passed - Status: %d (set only)", static_cast(testStatus)); - } - } else { - TEST_LOG("SetMigrationStatus failed for status %d with error: %d - Migration operations not available", - static_cast(testStatus), setResult); - TEST_LOG("Migration status sequence step passed - Status: %d (error handled)", static_cast(testStatus)); - } - } -} - -/** - * @brief Test Migration negative case - Interface not available - * @details Tests behavior when Migration interface is not available - */ -TEST_F(MigrationL2Test, NegativeTest_InterfaceNotAvailable) -{ - // Don't create the interface connection - test with null interface - ASSERT_EQ(mMigrationPlugin, nullptr) << "Migration plugin interface should be null for this test"; -} - -/** - * @brief Test Migration boot type enumeration coverage - * @details Verifies that GetBootTypeInfo covers all possible boot type values - * Note: This test handles both success and error cases gracefully, as BootType may not be configured in all environments - */ -TEST_F(MigrationL2Test, BootType_EnumerationCoverage) -{ - // Create bootType file for enumeration coverage test - const std::string bootTypeFile = "/tmp/bootType"; - const std::string bootTypeContent = "BOOT_TYPE=BOOT_NORMAL\n"; - - std::ofstream file(bootTypeFile); - if (file.is_open()) { - file << bootTypeContent; - file.close(); - TEST_LOG("Created bootType file with BOOT_NORMAL content"); - } - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::BootTypeInfo bootTypeInfo; - Core::hresult result = mMigrationPlugin->GetBootTypeInfo(bootTypeInfo); - - // Handle both success and error cases gracefully - if (result == Core::ERROR_NONE) { - // Log the current boot type - TEST_LOG("Current boot type: %d", static_cast(bootTypeInfo.bootType)); - - // Verify it's one of the valid enumeration values - bool isValidBootType = false; - switch (bootTypeInfo.bootType) { - case Exchange::IMigration::BootType::BOOT_TYPE_INIT: - TEST_LOG("Boot type is BOOT_TYPE_INIT"); - isValidBootType = true; - break; - case Exchange::IMigration::BootType::BOOT_TYPE_NORMAL: - TEST_LOG("Boot type is BOOT_TYPE_NORMAL"); - isValidBootType = true; - break; - case Exchange::IMigration::BootType::BOOT_TYPE_MIGRATION: - TEST_LOG("Boot type is BOOT_TYPE_MIGRATION"); - isValidBootType = true; - break; - case Exchange::IMigration::BootType::BOOT_TYPE_UPDATE: - TEST_LOG("Boot type is BOOT_TYPE_UPDATE"); - isValidBootType = true; - break; - default: - TEST_LOG("Unknown boot type: %d", static_cast(bootTypeInfo.bootType)); - isValidBootType = false; - break; - } - - EXPECT_TRUE(isValidBootType) << "Boot type enumeration coverage failed - invalid boot type: " - << static_cast(bootTypeInfo.bootType); - - TEST_LOG("BootType enumeration coverage test PASSED"); - } else { - TEST_LOG("GetBootTypeInfo returned error: %d - BootType not available/configured", result); - } - - // Clean up test file - std::remove(bootTypeFile.c_str()); -} - -/** - * @brief Test GetBootTypeInfo with invalid boot type value - * @details Tests GetBootTypeInfo when boot type file contains invalid/unknown value - * Should return an error or a fallback default value - */ -TEST_F(MigrationL2Test, GetBootTypeInfo_InvalidBootType) -{ - // Create bootType file with invalid content - const std::string bootTypeFile = "/tmp/bootType"; - const std::string bootTypeContent = "BOOT_TYPE=INVALID_BOOT_TYPE\n"; - - std::ofstream file(bootTypeFile); - ASSERT_TRUE(file.is_open()) << "Could not create bootType file for invalid test"; - file << bootTypeContent; - file.close(); - TEST_LOG("Created bootType file with invalid boot type content"); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::BootTypeInfo bootTypeInfo; - Core::hresult result = mMigrationPlugin->GetBootTypeInfo(bootTypeInfo); - - // For invalid boot type, the API should return an error OR a fallback value - if (result != Core::ERROR_NONE) { - TEST_LOG("GetBootTypeInfo correctly returned error: %d for invalid boot type", result); - } else { - // If it returns success, it should be a valid fallback value - EXPECT_TRUE(bootTypeInfo.bootType >= Exchange::IMigration::BootType::BOOT_TYPE_INIT && - bootTypeInfo.bootType <= Exchange::IMigration::BootType::BOOT_TYPE_UPDATE) - << "Invalid boot type fallback value: " << static_cast(bootTypeInfo.bootType); - TEST_LOG("GetBootTypeInfo returned fallback value: %d for invalid boot type", - static_cast(bootTypeInfo.bootType)); - } - - // Clean up test file - std::remove(bootTypeFile.c_str()); -} - -/** - * @brief Test GetBootTypeInfo with missing boot type file - * @details Tests GetBootTypeInfo when boot type file is missing - */ -TEST_F(MigrationL2Test, GetBootTypeInfo_MissingFile) -{ - // Ensure bootType file doesn't exist - const std::string bootTypeFile = "/tmp/bootType"; - std::remove(bootTypeFile.c_str()); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - Exchange::IMigration::BootTypeInfo bootTypeInfo; - Core::hresult result = mMigrationPlugin->GetBootTypeInfo(bootTypeInfo); - - // For missing file, the API should return an error - if (result != Core::ERROR_NONE) { - TEST_LOG("GetBootTypeInfo correctly returned error: %d for missing file", result); - } else { - TEST_LOG("GetBootTypeInfo returned success despite missing file - may be using system configuration"); - } -} - -/** - * @brief Test Migration status enumeration coverage - * @details Verifies that all migration status values can be set and retrieved - */ -TEST_F(MigrationL2Test, MigrationStatus_EnumerationCoverage) -{ - // Setup RFC mock to read from the file that SetMigrationStatus writes to - std::string lastWrittenStatus = "NOT_STARTED"; - - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillRepeatedly(testing::Invoke( - [&lastWrittenStatus](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, lastWrittenStatus.c_str()); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Test all valid migration status enumeration values - std::vector> allStatuses = { - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED, "NOT_STARTED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_NEEDED, "NOT_NEEDED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED, "STARTED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED, "PRIORITY_SETTINGS_MIGRATED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED, "DEVICE_SETTINGS_MIGRATED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_CLOUD_SETTINGS_MIGRATED, "CLOUD_SETTINGS_MIGRATED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_APP_DATA_MIGRATED, "APP_DATA_MIGRATED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED, "MIGRATION_COMPLETED"} - }; - - for (const auto& statusPair : allStatuses) { - // Update the mock to return the status we're about to set - lastWrittenStatus = statusPair.second; - - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus(statusPair.first, migrationResult); - - // Handle both success and error cases gracefully - if (setResult == Core::ERROR_NONE) { - EXPECT_TRUE(migrationResult.success) - << "SetMigrationStatus result indicates failure for " << statusPair.second; - - // Verify the status was set correctly - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - if (getResult == Core::ERROR_NONE) { - EXPECT_EQ(migrationStatusInfo.migrationStatus, statusPair.first) - << "Migration status verification failed for " << statusPair.second; - TEST_LOG("Migration status enumeration test passed for %s (%d) - verified", - statusPair.second.c_str(), static_cast(statusPair.first)); - } else { - TEST_LOG("SetMigrationStatus succeeded for %s but GetMigrationStatus failed with error: %d", - statusPair.second.c_str(), getResult); - TEST_LOG("Migration status enumeration test passed for %s (%d) - set only", - statusPair.second.c_str(), static_cast(statusPair.first)); - } - } else { - TEST_LOG("SetMigrationStatus failed for %s with error: %d - Migration operations not available", - statusPair.second.c_str(), setResult); - TEST_LOG("Migration status enumeration test passed for %s (%d) - error handled", - statusPair.second.c_str(), static_cast(statusPair.first)); - } - } -} - -/** - * @brief Test SetMigrationStatus API - Invalid Parameter Error - * @details Tests SetMigrationStatus with invalid migration status values - * and validates the exact expected error response - */ -TEST_F(MigrationL2Test, SetMigrationStatus_InvalidParameter) -{ - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Test with invalid migration status value (cast an invalid integer to enum) - Exchange::IMigration::MigrationStatus invalidStatus = - static_cast(9999); - - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus(invalidStatus, migrationResult); - - // The API should return ERROR_INVALID_PARAMETER or another error for invalid status - EXPECT_NE(setResult, Core::ERROR_NONE) << "SetMigrationStatus should have failed for invalid status: " << static_cast(invalidStatus); - - if (setResult == Core::ERROR_INVALID_PARAMETER) { - TEST_LOG("SetMigrationStatus correctly returned ERROR_INVALID_PARAMETER for invalid status: %d", - static_cast(invalidStatus)); - } else { - TEST_LOG("SetMigrationStatus returned appropriate error: %d for invalid status: %d", - setResult, static_cast(invalidStatus)); - } - - // Test with another boundary case - negative value cast to enum - Exchange::IMigration::MigrationStatus negativeStatus = - static_cast(-1); - - Core::hresult setResult2 = mMigrationPlugin->SetMigrationStatus(negativeStatus, migrationResult); - - EXPECT_NE(setResult2, Core::ERROR_NONE) << "SetMigrationStatus should have failed for negative status: " << static_cast(negativeStatus); - - if (setResult2 == Core::ERROR_INVALID_PARAMETER) { - TEST_LOG("SetMigrationStatus correctly returned ERROR_INVALID_PARAMETER for negative status: %d", - static_cast(negativeStatus)); - } else { - TEST_LOG("SetMigrationStatus returned appropriate error: %d for negative status: %d", - setResult2, static_cast(negativeStatus)); - } - - TEST_LOG("SetMigrationStatus invalid parameter test PASSED - Both invalid inputs returned errors"); -} - -/** - * @brief Test GetMigrationStatus API - RFC Parameter Success Scenarios - * @details Tests GetMigrationStatus when RFC parameter is successfully retrieved and mapped - */ -TEST_F(MigrationL2Test, GetMigrationStatus_RFCParameterSuccess) -{ - // Setup RFC mock for GetMigrationStatus - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "PRIORITY_SETTINGS_MIGRATED"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // First, set a known migration status to ensure there's a value to retrieve - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus( - Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_PRIORITY_SETTINGS_MIGRATED, migrationResult); - - if (setResult == Core::ERROR_NONE) { - TEST_LOG("Successfully set migration status to PRIORITY_SETTINGS_MIGRATED for RFC test"); - - // Now test retrieving the status to cover the string-to-status mapping - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - if (getResult == Core::ERROR_NONE) { - TEST_LOG("GetMigrationStatus successfully retrieved status: %d", - static_cast(migrationStatusInfo.migrationStatus)); - - // Verify the mapping worked correctly (string-to-enum conversion) - EXPECT_TRUE(migrationStatusInfo.migrationStatus >= Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED && - migrationStatusInfo.migrationStatus <= Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED) - << "Invalid migration status returned from RFC parameter mapping"; - - TEST_LOG("GetMigrationStatus RFC parameter success test PASSED - String-to-status mapping worked"); - } else { - TEST_LOG("GetMigrationStatus returned error: %d - RFC parameter not available", getResult); - } - } else { - TEST_LOG("Could not set initial migration status - RFC parameter test may not be fully effective"); - } -} - -/** - * @brief Test GetMigrationStatus API - RFC Parameter Failure Scenarios - * @details Tests GetMigrationStatus when RFC parameter retrieval fails - */ -TEST_F(MigrationL2Test, GetMigrationStatus_RFCParameterFailure) -{ - // Setup RFC mock to return failure - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Return(WDMP_FAILURE)); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // This test covers the scenario where getRFCParameter fails - // In most test environments, RFC may not be fully configured - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - if (getResult != Core::ERROR_NONE) { - TEST_LOG("GetMigrationStatus correctly returned error: %d for RFC parameter failure", getResult); - } else { - TEST_LOG("Migration status retrieved: %d", static_cast(migrationStatusInfo.migrationStatus)); - } -} - -/** - * @brief Test GetMigrationStatus API - Invalid RFC Value Scenarios - * @details Tests GetMigrationStatus when RFC parameter contains invalid/unmapped values - */ -TEST_F(MigrationL2Test, GetMigrationStatus_InvalidRFCValue) -{ - // Setup RFC mock to return invalid/unmapped value - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "INVALID_STATUS_VALUE"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Note: This test is challenging to implement directly since we can't easily - // inject invalid RFC values. However, we can test the scenario indirectly. - - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - // The test covers the scenario where RFC returns a value that's not in stringToStatus map - if (getResult != Core::ERROR_NONE) { - TEST_LOG("GetMigrationStatus returned error: %d", getResult); - } else { - TEST_LOG("GetMigrationStatus succeeded with valid RFC value: %d", - static_cast(migrationStatusInfo.migrationStatus)); - - // Verify it's a valid mapped value - bool isValidStatus = (migrationStatusInfo.migrationStatus >= Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED && - migrationStatusInfo.migrationStatus <= Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_MIGRATION_COMPLETED); - - if (isValidStatus) { - TEST_LOG("GetMigrationStatus invalid RFC value test PASSED - Valid mapping confirmed"); - } else { - TEST_LOG("GetMigrationStatus returned unexpected status value - may indicate mapping issue"); - } - } -} - -/** - * @brief Test Migration string-to-status mapping completeness - * @details Verifies that all status strings in implementation are properly mapped - */ -TEST_F(MigrationL2Test, GetMigrationStatus_StringMappingCompleteness) -{ - // Setup RFC mock to read from the file that SetMigrationStatus writes to - std::string lastWrittenStatus = "NOT_STARTED"; - - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillRepeatedly(testing::Invoke( - [&lastWrittenStatus](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, lastWrittenStatus.c_str()); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = CreateMigrationInterfaceObjectUsingComRPCConnection(); - ASSERT_EQ(status, Core::ERROR_NONE) << "Failed to create Migration COM-RPC interface"; - ASSERT_NE(mMigrationPlugin, nullptr) << "Migration plugin interface is null"; - - // Test that we can set and get all valid migration statuses - // This indirectly tests the string-to-status mapping in GetMigrationStatus - std::vector> testStatuses = { - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_STARTED, "NOT_STARTED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_NOT_NEEDED, "NOT_NEEDED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_STARTED, "STARTED"}, - {Exchange::IMigration::MigrationStatus::MIGRATION_STATUS_DEVICE_SETTINGS_MIGRATED, "DEVICE_SETTINGS_MIGRATED"} - }; - - int successfulMappings = 0; - int totalMappings = testStatuses.size(); - - for (const auto& statusPair : testStatuses) { - // Update the mock to return the status we're about to set - lastWrittenStatus = statusPair.second; - // Set the status - Exchange::IMigration::MigrationResult migrationResult; - Core::hresult setResult = mMigrationPlugin->SetMigrationStatus(statusPair.first, migrationResult); - - if (setResult == Core::ERROR_NONE) { - // Try to get it back - this tests the string-to-status mapping - Exchange::IMigration::MigrationStatusInfo migrationStatusInfo; - Core::hresult getResult = mMigrationPlugin->GetMigrationStatus(migrationStatusInfo); - - if (getResult == Core::ERROR_NONE && migrationStatusInfo.migrationStatus == statusPair.first) { - successfulMappings++; - TEST_LOG("String mapping verified for %s (%d)", - statusPair.second.c_str(), static_cast(statusPair.first)); - } else { - TEST_LOG("String mapping test inconclusive for %s - Get operation failed or RFC not configured", - statusPair.second.c_str()); - } - } else { - TEST_LOG("String mapping test skipped for %s - Set operation failed", statusPair.second.c_str()); - } - } - -} - -/**************************************************/ -// JSONRPC Test Cases -/**************************************************/ - -/** - * @brief Parameterized test class for GetBootTypeInfo JSONRPC tests with different boot types - */ -class GetBootTypeInfoJSONRPCTest : public MigrationL2Test, public ::testing::WithParamInterface> {}; - -/** - * @brief Parameterized test for GetBootTypeInfo via JSONRPC with different boot type values - * @details Tests GetBootTypeInfo JSONRPC method when boot type file contains different valid boot types - * and validates the exact expected string value is returned (JSONRPC returns strings) - */ -TEST_P(GetBootTypeInfoJSONRPCTest, GetBootTypeInfo_BootTypes_JSONRPC) -{ - const std::string bootTypeFile = "/tmp/bootType"; - const char* bootTypeString = GetParam().first; - const char* expectedBootTypeString = GetParam().second; - const std::string bootTypeContent = std::string("BOOT_TYPE=") + bootTypeString + "\n"; - - std::ofstream file(bootTypeFile); - ASSERT_TRUE(file.is_open()) << "Could not create bootType file for JSONRPC test"; - file << bootTypeContent; - file.close(); - TEST_LOG("Created bootType file with %s content", bootTypeString); - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.Migration", "getBootTypeInfo", params, result); - ASSERT_EQ(status, Core::ERROR_NONE) << "JSONRPC getBootTypeInfo failed for " << bootTypeString; - - ASSERT_TRUE(result.HasLabel("bootType")) << "Response missing 'bootType' field for " << bootTypeString; - - std::string actualBootType = result["bootType"].String(); - EXPECT_EQ(actualBootType, std::string(expectedBootTypeString)) - << "Boot type mismatch for " << bootTypeString - << " - Expected: '" << expectedBootTypeString << "', Got: '" << actualBootType << "'"; - - TEST_LOG("JSONRPC GetBootTypeInfo %s test PASSED - Expected and got boot type: '%s'", - bootTypeString, actualBootType.c_str()); - - std::remove(bootTypeFile.c_str()); -} - -INSTANTIATE_TEST_SUITE_P( - BootTypeJSONRPCTests, - GetBootTypeInfoJSONRPCTest, - ::testing::Values( - std::make_pair("BOOT_INIT", "BOOT_INIT"), // JSONRPC returns string values - std::make_pair("BOOT_MIGRATION", "BOOT_MIGRATION"), - std::make_pair("BOOT_UPDATE", "BOOT_UPDATE") // This was failing - expecting string not number - ) -); - -/** - * @brief Test GetBootTypeInfo with invalid boot type via JSONRPC - */ -TEST_F(MigrationL2Test, GetBootTypeInfo_InvalidBootType_JSONRPC) -{ - const std::string bootTypeFile = "/tmp/bootType"; - const std::string bootTypeContent = "BOOT_TYPE=INVALID_BOOT_TYPE\n"; - - std::ofstream file(bootTypeFile); - if (file.is_open()) { - file << bootTypeContent; - file.close(); - TEST_LOG("Created bootType file with invalid boot type content"); - } - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.Migration", "getBootTypeInfo", params, result); - // Accept both success (with fallback) or error - TEST_LOG("JSONRPC GetBootTypeInfo with invalid type completed with status: %d", status); - - std::remove(bootTypeFile.c_str()); -} - -/** - * @brief Test GetBootTypeInfo with missing file via JSONRPC - */ -TEST_F(MigrationL2Test, GetBootTypeInfo_MissingFile_JSONRPC) -{ - const std::string bootTypeFile = "/tmp/bootType"; - std::remove(bootTypeFile.c_str()); - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.Migration", "getBootTypeInfo", params, result); - TEST_LOG("JSONRPC GetBootTypeInfo with missing file completed with status: %d", status); -} - -/** - * @brief Test Migration status enumeration coverage via JSONRPC - * @details Verifies that all migration status values can be set via JSONRPC - * and validates both the success response and proper value storage - */ -TEST_F(MigrationL2Test, MigrationStatus_EnumerationCoverage_JSONRPC) -{ - // Setup RFC mock to read from the file that SetMigrationStatus writes to - std::string lastWrittenStatus = "NOT_STARTED"; - - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillRepeatedly(testing::Invoke( - [&lastWrittenStatus](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, lastWrittenStatus.c_str()); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - // Map of status value to string for updating the mock - static const std::unordered_map statusToString = { - { 0, "NOT_STARTED" }, - { 1, "NOT_NEEDED" }, - { 2, "STARTED" }, - { 3, "PRIORITY_SETTINGS_MIGRATED" }, - { 4, "DEVICE_SETTINGS_MIGRATED" }, - { 5, "CLOUD_SETTINGS_MIGRATED" }, - { 6, "APP_DATA_MIGRATED" }, - { 7, "MIGRATION_COMPLETED" } - }; - - // Test all valid migration status enumeration values with exact validation - std::vector allStatuses = {0, 1, 2, 3, 4, 5, 6, 7}; - - for (auto statusValue : allStatuses) { - // Update the mock to return the status we're about to set - auto it = statusToString.find(statusValue); - if (it != statusToString.end()) { - lastWrittenStatus = it->second; - } - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - params["migrationStatus"] = statusValue; - - status = InvokeServiceMethod("org.rdk.Migration", "setMigrationStatus", params, result); - ASSERT_EQ(status, Core::ERROR_NONE) << "JSONRPC setMigrationStatus failed for status: " << statusValue; - - ASSERT_TRUE(result.HasLabel("success")) << "Response missing 'success' field for status: " << statusValue; - EXPECT_TRUE(result["success"].Boolean()) << "SetMigrationStatus failed for status: " << statusValue; - - // Verify the status was actually set by reading it back via JSONRPC - JsonObject getParams, getResult; - uint32_t getStatus = InvokeServiceMethod("org.rdk.Migration", "getMigrationStatus", getParams, getResult); - - if (getStatus == Core::ERROR_NONE && getResult.HasLabel("migrationStatus")) { - // Handle both string and numeric responses like L1 tests do - const Core::JSON::Variant& statusResponse = getResult["migrationStatus"]; - std::string actualStatusString; - int actualStatusNumber = -1; - - // Try to get as string first - actualStatusString = statusResponse.String(); - - // If string is empty, it might be a number - try that - if (actualStatusString.empty()) { - actualStatusNumber = statusResponse.Number(); - TEST_LOG("DEBUG: migrationStatus appears to be numeric: %d for expected status %d", actualStatusNumber, statusValue); - - // For numeric comparison, compare directly - EXPECT_EQ(actualStatusNumber, statusValue) - << "Migration status verification failed for status: " << statusValue - << " - Expected: " << statusValue << ", Got: " << actualStatusNumber; - } else { - // For string responses, map the expected status number to string for comparison - auto it = statusToString.find(statusValue); - if (it != statusToString.end()) { - EXPECT_EQ(actualStatusString, it->second) - << "Migration status verification failed for status: " << statusValue - << " - Expected: " << it->second << ", Got: " << actualStatusString; - } else { - TEST_LOG("Warning: No string mapping for status %d", statusValue); - } - } - TEST_LOG("Migration status enumeration test passed for status %d - set and verified correctly", statusValue); - } else { - TEST_LOG("Migration status enumeration test passed for status %d - set only (RFC not configured)", statusValue); - } - } -} - -/** - * @brief Test SetMigrationStatus with invalid parameter via JSONRPC - * @details Tests SetMigrationStatus JSONRPC method with invalid status value - * Documents that the API currently accepts invalid values (lenient validation) - */ -TEST_F(MigrationL2Test, SetMigrationStatus_InvalidParameter_JSONRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - // Test with invalid migration status value - params["migrationStatus"] = 9999; - - status = InvokeServiceMethod("org.rdk.Migration", "setMigrationStatus", params, result); - - // The API currently accepts invalid parameters and returns success (lenient validation) - EXPECT_EQ(status, Core::ERROR_NONE) << "API returned unexpected error status for invalid parameter"; - - ASSERT_TRUE(result.HasLabel("success")) << "Response missing 'success' field for invalid parameter"; - bool success = result["success"].Boolean(); - EXPECT_TRUE(success) << "API currently accepts invalid parameters and returns success:true (unexpected but documented behavior)"; - - TEST_LOG("JSONRPC SetMigrationStatus test PASSED - API accepts invalid parameter %d with success:true (lenient validation)", 9999); -} - -/** - * @brief Test GetMigrationStatus RFC parameter success via JSONRPC - * @details Tests GetMigrationStatus JSONRPC method when RFC parameter returns specific value - * and validates the exact expected string status is returned (API returns strings) - */ -TEST_F(MigrationL2Test, GetMigrationStatus_RFCParameterSuccess_JSONRPC) -{ - // Setup RFC mock to return specific expected value - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Invoke( - [](const char* arg1, const char* arg2, RFC_ParamData_t* arg3) -> WDMP_STATUS { - if (arg3 != nullptr) { - strcpy(arg3->value, "PRIORITY_SETTINGS_MIGRATED"); - arg3->type = WDMP_STRING; - } - return WDMP_SUCCESS; - })); - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.Migration", "getMigrationStatus", params, result); - ASSERT_EQ(status, Core::ERROR_NONE) << "JSONRPC getMigrationStatus failed"; - - ASSERT_TRUE(result.HasLabel("migrationStatus")) << "Response missing 'migrationStatus' field"; - - // Handle both string and numeric responses like L1 tests do - const Core::JSON::Variant& migrationStatusResponse = result["migrationStatus"]; - std::string statusAsString; - int statusAsNumber = -1; - - // Try to get as string first (expected for this API) - statusAsString = migrationStatusResponse.String(); - - // If string is empty, it might be a number - try that - if (statusAsString.empty()) { - statusAsNumber = migrationStatusResponse.Number(); - TEST_LOG("DEBUG: migrationStatus appears to be numeric: %d", statusAsNumber); - - // PRIORITY_SETTINGS_MIGRATED should map to status value 3 - EXPECT_EQ(statusAsNumber, 3) - << "Migration status from RFC mismatch - Expected: 3 (PRIORITY_SETTINGS_MIGRATED), Got: " << statusAsNumber; - TEST_LOG("GetMigrationStatus JSONRPC RFC success test PASSED - Numeric status: %d", statusAsNumber); - } else { - // For string response, expect the exact string (this should be the case) - EXPECT_EQ(statusAsString, "PRIORITY_SETTINGS_MIGRATED") - << "Migration status from RFC mismatch - Expected: 'PRIORITY_SETTINGS_MIGRATED', Got: '" << statusAsString << "'"; - TEST_LOG("GetMigrationStatus JSONRPC RFC success test PASSED - String status: '%s'", statusAsString.c_str()); - } -} - -/** - * @brief Test GetMigrationStatus RFC parameter failure via JSONRPC - */ -TEST_F(MigrationL2Test, GetMigrationStatus_RFCParameterFailure_JSONRPC) -{ - // Setup RFC mock to return failure - EXPECT_CALL(*p_rfcApiImplMock, getRFCParameter(testing::_, testing::StrEq("Device.DeviceInfo.Migration.MigrationStatus"), testing::_)) - .WillOnce(testing::Return(WDMP_FAILURE)); - - uint32_t status = Core::ERROR_GENERAL; - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.Migration", "getMigrationStatus", params, result); - TEST_LOG("JSONRPC GetMigrationStatus with RFC failure completed with status: %d", status); -} - diff --git a/Tests/L2Tests/tests/OCIContainer_L2Test.cpp b/Tests/L2Tests/tests/OCIContainer_L2Test.cpp deleted file mode 100644 index 0d65b00..0000000 --- a/Tests/L2Tests/tests/OCIContainer_L2Test.cpp +++ /dev/null @@ -1,2724 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include - -#define EVNT_TIMEOUT (5000) -#define OCICONTAINER_CALLSIGN _T("org.rdk.OCIContainer.1") -#define OCICONTAINERTEST_CALLSIGN _T("L2tests.1") - -#define TEST_LOG(x, ...) \ - fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); \ - fflush(stderr); - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ContainerState = WPEFramework::Exchange::IOCIContainer::ContainerState; -using OmiErrorListener = omi::IOmiProxy::OmiErrorListener; - -typedef enum : uint32_t { - - ON_CONTAINER_STARTED = 0x00000001, - ON_CONTAINER_STOPPED = 0x00000002, - ON_CONTAINER_FAILED = 0x00000003, - ON_CONTAINER_STATECHANGED = 0x00000004, - OCICONTAINER_STATUS_INVALID = 0x00000000 - -} OCIContainerL2test_async_events_t; - -class AsyncHandlerMock_OCIContainer { -public: - AsyncHandlerMock_OCIContainer() - { - } - MOCK_METHOD(void, onContainerStarted, (const JsonObject& message)); - MOCK_METHOD(void, onContainerStopped, (const JsonObject& message)); - MOCK_METHOD(void, onContainerFailed, (const JsonObject& message)); - MOCK_METHOD(void, onContainerStateChanged, (const JsonObject& message)); -}; - -// Notification Handler Class for OCIContainer -class OCIContainerNotificationHandler : public Exchange::IOCIContainer::INotification { -private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IOCIContainer::INotification) - END_INTERFACE_MAP - -public: - OCIContainerNotificationHandler() {} - ~OCIContainerNotificationHandler() {} - - // OCIContainer notifications - void OnContainerStarted(const string& containerId, const string& name) override - { - TEST_LOG("OnContainerStarted event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnContainerStarted received (CONTAINER ID): %s\n", containerId.c_str()); - TEST_LOG("OnContainerStarted received (NAME): %s\n", name.c_str()); - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STARTED; - m_condition_variable.notify_one(); - } - - void OnContainerStopped(const string& containerId, const string& name) override - { - TEST_LOG("OnContainerStopped event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnContainerStopped received (CONTAINER ID): %s\n", containerId.c_str()); - TEST_LOG("OnContainerStopped received (NAME): %s\n", name.c_str()); - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STOPPED; - m_condition_variable.notify_one(); - } - - void OnContainerFailed(const string& containerId, const string& name, uint32_t error) override - { - TEST_LOG("OnContainerFailed event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnContainerFailed received (CONTAINER ID): %s\n", containerId.c_str()); - TEST_LOG("OnContainerFailed received (NAME): %s\n", name.c_str()); - TEST_LOG("OnContainerFailed received (ERROR): %u\n", error); - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_FAILED; - m_condition_variable.notify_one(); - } - - void OnContainerStateChanged(const string& containerId, ContainerState state) override - { - TEST_LOG("OnContainerStateChanged event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnContainerStateChanged received (CONTAINER ID): %s\n", containerId.c_str()); - TEST_LOG("OnContainerStateChanged received (STATE): %d\n", state); - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STATECHANGED; // Use a specific flag for state change - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, OCIContainerL2test_async_events_t expected_status) - { - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - - while (!(expected_status & m_event_signalled)) { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; - } -}; - -class OCIContainer_L2Test : public L2TestMocks { -protected: - OCIContainer_L2Test(); - virtual ~OCIContainer_L2Test() override; - -public: - void onContainerStarted(const JsonObject& data); - void onContainerStopped(const JsonObject& data); - void onContainerFailed(const JsonObject& data); - void onContainerStateChanged(const JsonObject& data); - uint32_t WaitForRequestStatus(uint32_t timeout_ms, OCIContainerL2test_async_events_t expected_status); - uint32_t CreateOCIContainerInterfaceObject(); - - StateChangeListener storedListener = nullptr; - const void* storedCbParams = nullptr; - OmiErrorListener storedOmiListener = nullptr; - const void* storedOmiCbParams = nullptr; - - void triggerStateChangeEvent(int32_t id, const std::string& name, IDobbyProxyEvents::ContainerState state) - { - if (storedListener) { - storedListener(id, name, state, storedCbParams); - } - } - - void triggerOmiErrorEvent(const std::string& id, omi::IOmiProxy::ErrorType err) - { - if (storedOmiListener) { - storedOmiListener(id, err, storedOmiCbParams); - } - } - -private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - -protected: - Core::ProxyType> OCIcontainer_Engine; - Core::ProxyType OCIcontainer_Client; - - /** @brief Pointer to the IShell interface */ - PluginHost::IShell* m_controller_OCIcontainer; - - /** @brief Pointer to the IOCIContainerinterface */ - Exchange::IOCIContainer* m_OCIContainerplugin; -}; - -OCIContainer_L2Test::OCIContainer_L2Test() - : L2TestMocks() -{ - uint32_t status = Core::ERROR_GENERAL; - - EXPECT_CALL(*p_ipcservicemock, start()) - .WillOnce(::testing::Return(true)); - - EXPECT_CALL(*p_dobbyProxyMock, registerListener(::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke([&](const StateChangeListener& listener, const void* cbParams) { - storedListener = listener; - storedCbParams = cbParams; - return 5; // Return a mock listener ID - })); - - EXPECT_CALL(*p_mockOmiProxy, registerListener(::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke([&](const OmiErrorListener& listener, const void* cbParams) { - storedOmiListener = listener; - storedOmiCbParams = cbParams; - return 6; // Return a mock listener ID - })); - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.OCIContainer"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -OCIContainer_L2Test::~OCIContainer_L2Test() -{ - uint32_t status = Core::ERROR_GENERAL; - - /* Deactivate plugin in destructor */ - status = DeactivateService("org.rdk.OCIContainer"); - EXPECT_EQ(Core::ERROR_NONE, status); - - sleep(2); // Added sleep due to failures while activating/deactivating the plugin -} - -uint32_t OCIContainer_L2Test::CreateOCIContainerInterfaceObject() -{ - uint32_t return_value = Core::ERROR_GENERAL; - - TEST_LOG("Creating OCIcontainer_Engine"); - OCIcontainer_Engine = Core::ProxyType>::Create(); - OCIcontainer_Client = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(OCIcontainer_Engine)); - - TEST_LOG("Creating OCIcontainer_Engine Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - OCIcontainer_Engine->Announcements(mOCIcontainer_Client->Announcement()); -#endif - if (!OCIcontainer_Client.IsValid()) { - TEST_LOG("Invalid OCIcontainer_Client"); - } else { - m_controller_OCIcontainer = OCIcontainer_Client->Open(_T("org.rdk.OCIContainer"), ~0, 3000); - if (m_controller_OCIcontainer) { - m_OCIContainerplugin = m_controller_OCIcontainer->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -uint32_t OCIContainer_L2Test::WaitForRequestStatus(uint32_t timeout_ms, OCIContainerL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - - while (!(expected_status & m_event_signalled)) { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void OCIContainer_L2Test::onContainerStarted(const JsonObject& data) -{ - TEST_LOG("OnContainerStarted event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - data.ToString(str); - - TEST_LOG("OnContainerStarted received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STARTED; - m_condition_variable.notify_one(); -} - -void OCIContainer_L2Test::onContainerStopped(const JsonObject& data) -{ - TEST_LOG("OnContainerStopped event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - data.ToString(str); - - TEST_LOG("OnContainerStopped received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STOPPED; - m_condition_variable.notify_one(); -} - -void OCIContainer_L2Test::onContainerFailed(const JsonObject& data) -{ - TEST_LOG("OnContainerFailed event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - data.ToString(str); - - TEST_LOG("OnContainerFailed received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_FAILED; - m_condition_variable.notify_one(); -} - -void OCIContainer_L2Test::onContainerStateChanged(const JsonObject& data) -{ - TEST_LOG("OnContainerStateChanged event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - data.ToString(str); - - TEST_LOG("OnContainerStateChanged received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= ON_CONTAINER_STATECHANGED; - m_condition_variable.notify_one(); -} - -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s", expected.c_str(), actual.c_str()); - EXPECT_STREQ(expected.c_str(), actual.c_str()); - - return match; -} - -/* - * Test case to list containers using COMRPC - * This test case verifies the ListContainers method of the OCIContainer plugin. - */ -TEST_F(OCIContainer_L2Test, ListContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containers, errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - status = m_OCIContainerplugin->ListContainers(containers, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - TEST_LOG("ListContainers returned containers: %s, success: %d, errorReason: %s", containers.c_str(), success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to test the GetContainerInfo method of OCIContainer plugin using COMRPC. - * This test case verifies that the GetContainerInfo method returns the correct information - * for a given container ID. - */ -TEST_F(OCIContainer_L2Test, GetContainerInfo_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string info, errorReason; - bool success = false; - - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerInfo(91)) - .WillOnce(::testing::Return("{\"cpu\":{\"usage\" :{\"percpu\" :[3661526845,3773518079,4484546066,4700379608]," - "\"total\" : 16619970598}},\"gpu\":{\"memory\" :{\"failcnt\" : 0,\"limit\" : 209715200,\"max\" : 3911680,\"usage\" : 0}}," - "\"id\":\"Cobalt-0\",\"ion\":{\"heaps\" :{\"ion.\" :{\"failcnt\" : null,\"limit\" : null,\"max\" : null,\"usage\" : null}}}," - "\"memory\":{\"user\" :{\"failcnt\" : 0,\"limit\" : 419430400,\"max\" : 73375744,\"usage\" : 53297152}},\"pids\":[13132,13418]," - "\"processes\":[{\"cmdline\" : \"/usr/libexec/DobbyInit /usr/bin/WPEProcess -l libWPEFrameworkCobaltImpl.so -c" - " CobaltImplementation -C Cobalt-0 -r /tmp/communicator -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s" - " \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\" -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m" - " \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : \"/usr/libexec/DobbyInit\",\"nsPid\" : 1," - "\"pid\" : 13132},{\"cmdline\" : \"WPEProcess -l libWPEFrameworkCobaltImpl.so -c CobaltImplementation -C Cobalt-0 -r /tmp/communicator" - " -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\"" - " -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : " - "\"/usr/bin/WPEProcess\",\"nsPid\" : 6,\"pid\" : 13418}],\"state\":\"running\",\"timestamp\":1298657054196}")); - - status = m_OCIContainerplugin->GetContainerInfo(containerID, info, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - TEST_LOG("GetContainerInfo returned info: %s, success: %d, errorReason: %s", info.c_str(), success, errorReason.c_str()); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the STARTING state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - */ -TEST_F(OCIContainer_L2Test, ListContainer_STARTING_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Starting)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::STARTING); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the RUNNING state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - */ -TEST_F(OCIContainer_L2Test, ListContainer_RUNNING_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Running)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::RUNNING); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the STOPPING state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as STOPPING when the container is in that state. - */ -TEST_F(OCIContainer_L2Test, ListContainer_STOPPING_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Stopping)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::STOPPING); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the PAUSED state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as PAUSED when the container is in that state. - */ -TEST_F(OCIContainer_L2Test, ListContainer_PAUSED_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Paused)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::PAUSED); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the STOPPED state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as STOPPED when the container is in that state. - */ -TEST_F(OCIContainer_L2Test, ListContainer_STOPPED_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Stopped)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::STOPPED); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the HIBERNATING state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as HIBERNATING when the container is in that state. - */ - -TEST_F(OCIContainer_L2Test, ListContainer_HIBERNATING_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Hibernating)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::HIBERNATING); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the HIBERNATED state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as HIBERNATED when the container is in that state. - */ -TEST_F(OCIContainer_L2Test, ListContainer_HIBERNATED_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Hibernated)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::HIBERNATED); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the AWAKENING state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as AWAKENING when the container is in that state. - */ - -TEST_F(OCIContainer_L2Test, ListContainer_AWAKENING_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Awakening)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::AWAKENING); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get the INVALID state of a container using COMRPC - * This test case verifies the GetContainerState method of the OCIContainer plugin. - * It checks if the state is correctly returned as INVALID when the container is in that state. - */ -TEST_F(OCIContainer_L2Test, ListContainer_INVALID_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerState(91)) - .WillOnce(::testing::Return(IDobbyProxyEvents::ContainerState::Invalid)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(state, ContainerState::INVALID); - EXPECT_TRUE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to start a container using COMRPC - * This test case verifies the StartContainer method of the OCIContainer plugin. - * It checks if the container can be started successfully and if the correct descriptor is returned. - */ -TEST_F(OCIContainer_L2Test, StartContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - string containerID = "com.bskyb.epgui", bundlepath = "/containers/myBundle", command = "command", westerOSSocket = "/usr/mySocket"; - int32_t descriptor = 0; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromBundle(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - status = m_OCIContainerplugin->StartContainer(containerID, bundlepath, command, westerOSSocket, descriptor, success, errorReason); - - // manually trigger the state change event for the container - // as the mock does not trigger it - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, containerID, IDobbyProxyEvents::ContainerState::Starting); - - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - TEST_LOG("StartContainer returned descriptor: %d, errorReason: %s", descriptor, errorReason.c_str()); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to start a container from a Dobby spec using COMRPC - * This test case verifies the StartContainerFromDobbySpec method of the OCIContainer plugin. - * It checks if the container can be started successfully and if the correct descriptor is returned. - */ -TEST_F(OCIContainer_L2Test, StartContainerFromDobbySpec_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - string containerID = "com.bskyb.epgui", dobbySpec = "/containers/dobbySpec", command = "command", westerOSSocket = "/usr/mySocket"; - int32_t descriptor = 0; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromSpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - status = m_OCIContainerplugin->StartContainerFromDobbySpec(containerID, dobbySpec, command, westerOSSocket, descriptor, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - TEST_LOG("StartContainerFromDobbySpec returned descriptor: %d, errorReason: %s", descriptor, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to stop a container using COMRPC - * This test case verifies the StopContainer method of the OCIContainer plugin. - * It checks if the container can be stopped successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, StopContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - string containerID = "com.bskyb.epgui"; - bool force = true; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->StopContainer(containerID, force, success, errorReason); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, containerID, IDobbyProxyEvents::ContainerState::Stopping); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to pause a container using COMRPC - * This test case verifies the PauseContainer method of the OCIContainer plugin. - * It checks if the container can be paused successfully and if the correct status and error reason are returned. - */ -TEST_F(OCIContainer_L2Test, PauseContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, pauseContainer(91)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->PauseContainer(containerID, success, errorReason); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, containerID, IDobbyProxyEvents::ContainerState::Paused); - - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to resume a container using COMRPC - * This test case verifies the ResumeContainer method of the OCIContainer plugin. - * It checks if the container can be resumed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, ResumeContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, resumeContainer(91)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->ResumeContainer(containerID, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to hibernate a container using COMRPC - * This test case verifies the HibernateContainer method of the OCIContainer plugin. - * It checks if the container can be hibernated successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, HibernateContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - string containerID = "com.bskyb.epgui"; - string errorReason, options; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, hibernateContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->HibernateContainer(containerID, options, success, errorReason); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, containerID, IDobbyProxyEvents::ContainerState::Hibernating); - - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to wake up a hibernated container using COMRPC - * This test case verifies the WakeupContainer method of the OCIContainer plugin. - * It checks if the container can be woken up successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, WakeupContainer_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, wakeupContainer(91)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->WakeupContainer(containerID, success, errorReason); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, containerID, IDobbyProxyEvents::ContainerState::Awakening); - - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to execute a command in a container using COMRPC - * This test case verifies the ExecuteCommand method of the OCIContainer plugin. - * It checks if the command can be executed successfully in the specified container. - */ -TEST_F(OCIContainer_L2Test, ExecuteCommand_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, options, command; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, execInContainer(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->ExecuteCommand(containerID, options, command, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to annotate a container using COMRPC - * This test case verifies the Annotate method of the OCIContainer plugin. - * It checks if the annotation can be added successfully to the specified container. - */ -TEST_F(OCIContainer_L2Test, Annotate_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, key, value; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addAnnotation(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->Annotate(containerID, key, value, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to remove an annotation from a container using COMRPC - * This test case verifies the RemoveAnnotation method of the OCIContainer plugin. - * It checks if the annotation can be removed successfully from the specified container. - */ -TEST_F(OCIContainer_L2Test, RemoveAnnotation_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, key; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeAnnotation(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->RemoveAnnotation(containerID, key, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to mount a source to a target in a container using COMRPC - * This test case verifies the Mount method of the OCIContainer plugin. - * It checks if the mount operation can be performed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, Mount_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, source, target, type, options; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addContainerMount(91, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->Mount(containerID, source, target, type, options, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to unmount a target from a container using COMRPC - * This test case verifies the Unmount method of the OCIContainer plugin. - * It checks if the unmount operation can be performed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, Unmount_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, target; - bool success = false; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeContainerMount(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - status = m_OCIContainerplugin->Unmount(containerID, target, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(success); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to get container information using JSONRPC - * This test case verifies the getContainerInfo method of the OCIContainer plugin. - * It checks if the container information can be retrieved successfully and if the correct data is returned. - */ -TEST_F(OCIContainer_L2Test, getcontainerInfo_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerInfo(91)) - .WillOnce(::testing::Return("{\"cpu\":{\"usage\" :{\"percpu\" :[3661526845,3773518079,4484546066,4700379608]," - "\"total\" : 16619970598}},\"gpu\":{\"memory\" :{\"failcnt\" : 0,\"limit\" : 209715200,\"max\" : 3911680,\"usage\" : 0}}," - "\"id\":\"Cobalt-0\",\"ion\":{\"heaps\" :{\"ion.\" :{\"failcnt\" : null,\"limit\" : null,\"max\" : null,\"usage\" : null}}}," - "\"memory\":{\"user\" :{\"failcnt\" : 0,\"limit\" : 419430400,\"max\" : 73375744,\"usage\" : 53297152}},\"pids\":[13132,13418]," - "\"processes\":[{\"cmdline\" : \"/usr/libexec/DobbyInit /usr/bin/WPEProcess -l libWPEFrameworkCobaltImpl.so -c" - " CobaltImplementation -C Cobalt-0 -r /tmp/communicator -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s" - " \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\" -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m" - " \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : \"/usr/libexec/DobbyInit\",\"nsPid\" : 1," - "\"pid\" : 13132},{\"cmdline\" : \"WPEProcess -l libWPEFrameworkCobaltImpl.so -c CobaltImplementation -C Cobalt-0 -r /tmp/communicator" - " -i 64 -x 48 -p \"/opt/persistent/rdkservices/Cobalt-0/\" -s \"/usr/lib/wpeframework/plugins/\" -d \"/usr/share/WPEFramework/Cobalt/\"" - " -a \"/usr/bin/\" -v \"/tmp/Cobalt-0/\" -m \"/usr/lib/wpeframework/proxystubs/\" -P \"/opt/minidumps/\" \",\"executable\" : " - "\"/usr/bin/WPEProcess\",\"nsPid\" : 6,\"pid\" : 13418}],\"state\":\"running\",\"timestamp\":1298657054196}")); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "getContainerInfo", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to start a container using JSONRPC - * This test case verifies the startContainer method of the OCIContainer plugin. - * It checks if the container can be started successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, Startcontainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromBundle(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStateChanged"), - &AsyncHandlerMock_OCIContainer::onContainerStateChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"state\":\"STARTING\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStateChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStateChanged)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["bundlePath"] = "/containers/myBundle"; - params["command"] = "command"; - params["westerosSocket"] = "/usr/mySocket"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "startContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - // manually trigger the state change event for the container - // as the mock does not trigger it - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Starting); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStateChanged")); -} - -/* - * Test case to start a container from a Dobby spec using JSONRPC - * This test case verifies the startContainerFromDobbySpec method of the OCIContainer plugin. - * It checks if the container can be started successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, StartcontainerFromDobbySpec_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromSpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(91)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["dobbySpec"] = "/containers/dobbySpec"; - params["command"] = "command"; - params["westerosSocket"] = "/usr/mySocket"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "startContainerFromDobbySpec", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to stop a container using JSONRPC - * This test case verifies the stopContainer method of the OCIContainer plugin. - * It checks if the container can be stopped successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, StopContainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStateChanged"), - &AsyncHandlerMock_OCIContainer::onContainerStateChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"state\":\"STOPPING\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStateChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStateChanged)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["force"] = true; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "stopContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Stopping); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStateChanged")); -} - -/* - * Test case to pause a container using JSONRPC - * This test case verifies the pauseContainer method of the OCIContainer plugin. - * It checks if the container can be paused successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, PauseContainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStateChanged"), - &AsyncHandlerMock_OCIContainer::onContainerStateChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"state\":\"PAUSED\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStateChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStateChanged)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, pauseContainer(91)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "pauseContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Paused); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStateChanged")); -} - -/* - * Test case to resume a container using JSONRPC - * This test case verifies the resumeContainer method of the OCIContainer plugin. - * It checks if the container can be resumed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, ResumeContainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, resumeContainer(91)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "resumeContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to hibernate a container using JSONRPC - * This test case verifies the hibernateContainer method of the OCIContainer plugin. - * It checks if the container can be hibernated successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, HibernateContainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStateChanged"), - &AsyncHandlerMock_OCIContainer::onContainerStateChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"state\":\"HIBERNATING\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStateChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStateChanged)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, hibernateContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["options"] = ""; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "hibernateContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(91, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Hibernating); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STATECHANGED); - EXPECT_TRUE(signalled & ON_CONTAINER_STATECHANGED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStateChanged")); -} - -/* - * Test case to wake up a hibernated container using JSONRPC - * This test case verifies the wakeupContainer method of the OCIContainer plugin. - * It checks if the container can be woken up successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, WakeupContainer_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, wakeupContainer(91)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "wakeupContainer", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to execute a command in a container using JSONRPC - * This test case verifies the executeCommand method of the OCIContainer plugin. - * It checks if the command can be executed successfully in the specified container. - */ -TEST_F(OCIContainer_L2Test, ExecuteCommand_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, execInContainer(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["options"] = ""; - params["command"] = "command"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "executeCommand", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to annotate a container using JSONRPC - * This test case verifies the annotate method of the OCIContainer plugin. - * It checks if the annotation can be added successfully to the specified container. - */ -TEST_F(OCIContainer_L2Test, Annotate_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addAnnotation(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["key"] = "key"; - params["value"] = "value"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "annotate", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to remove an annotation from a container using JSONRPC - * This test case verifies the removeAnnotation method of the OCIContainer plugin. - * It checks if the annotation can be removed successfully from the specified container. - */ -TEST_F(OCIContainer_L2Test, RemoveAnnotation_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeAnnotation(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["key"] = "key"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "removeAnnotation", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to mount a source to a target in a container using JSONRPC - * This test case verifies the mount method of the OCIContainer plugin. - * It checks if the mount operation can be performed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, Mount_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addContainerMount(91, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["source"] = "source"; - params["target"] = "target"; - params["type"] = "type"; - params["options"] = "options"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "mount", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to unmount a target from a container using JSONRPC - * This test case verifies the unmount method of the OCIContainer plugin. - * It checks if the unmount operation can be performed successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, Unmount_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeContainerMount(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - JsonObject params, result; - params["containerId"] = "com.bskyb.epgui"; - params["target"] = "target"; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "unmount", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to list all containers using JSONRPC - * This test case verifies the listContainers method of the OCIContainer plugin. - * It checks if the list of containers can be retrieved successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, ListContainers_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - JsonObject params, result; - - status = InvokeServiceMethod("org.rdk.OCIContainer", "listContainers", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to get the status of a container using JSONRPC - * This test case verifies the getContainerStatus method of the OCIContainer plugin. - * It checks if the status of the specified container can be retrieved successfully and if the correct status is returned. - */ -TEST_F(OCIContainer_L2Test, ContainerStopped_EventTest) -{ - Core::Sink notify; - string containerID = "com.bskyb.epgui"; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - int32_t descriptor = 91; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - EXPECT_CALL(*p_mockOmiProxy, umountCryptedBundle(::testing::_)) - .WillOnce(::testing::Return(true)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(descriptor, containerID, IDobbyProxyEvents::ContainerState::Stopped); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STOPPED); - EXPECT_TRUE(signalled & ON_CONTAINER_STOPPED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to verify the ON_CONTAINER_STARTED event - * This test case checks if the ON_CONTAINER_STARTED event is triggered correctly when a container starts. - * It uses a mock to simulate the container state change and verifies the event notification. - */ -TEST_F(OCIContainer_L2Test, ContainerStarted_EventTest) -{ - Core::Sink notify; - string containerID = "com.bskyb.epgui"; - int32_t descriptor = 91; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(descriptor, containerID, IDobbyProxyEvents::ContainerState::Running); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STARTED); - EXPECT_TRUE(signalled & ON_CONTAINER_STARTED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to verify the ON_CONTAINER_FAILED event - * This test case checks if the ON_CONTAINER_FAILED event is triggered correctly when a container fails. - * It uses a mock to simulate the container failure and verifies the event notification. - */ -TEST_F(OCIContainer_L2Test, ContainerFailed_EventTest) -{ - Core::Sink notify; - string containerID = "com.bskyb.epgui"; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - m_OCIContainerplugin->Register(¬ify); - - EXPECT_CALL(*p_dobbyProxyMock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - // manually trigger the state change event for the container - // as the mock does not trigger it - this->triggerOmiErrorEvent(containerID, omi::IOmiProxy::ErrorType::verityFailed); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_FAILED); - EXPECT_TRUE(signalled & ON_CONTAINER_FAILED); - - m_OCIContainerplugin->Unregister(¬ify); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to verify the ON_CONTAINER_STOPPED event - * This test case checks if the ON_CONTAINER_STOPPED event is triggered correctly when a container stops. - * It uses a mock to simulate the container state change and verifies the event notification. - */ -TEST_F(OCIContainer_L2Test, ContainerStoppedEvent_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - int32_t descriptor = 91; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStopped"), - &AsyncHandlerMock_OCIContainer::onContainerStopped, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"name\":\"com.bskyb.epgui\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStopped(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStopped)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(descriptor, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Stopped); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STOPPED); - EXPECT_TRUE(signalled & ON_CONTAINER_STOPPED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStopped")); -} - -/* - * Test case to verify the ON_CONTAINER_STARTED event - * This test case checks if the ON_CONTAINER_STARTED event is triggered correctly when a container starts. - * It uses a mock to simulate the container state change and verifies the event notification. - */ -TEST_F(OCIContainer_L2Test, ContainerStartedEvent_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - int32_t descriptor = 91; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerStarted"), - &AsyncHandlerMock_OCIContainer::onContainerStarted, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"name\":\"com.bskyb.epgui\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerStarted(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerStarted)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - // manually trigger the state change event for the container - // as the mock does not trigger it - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - this->triggerStateChangeEvent(descriptor, "com.bskyb.epgui", IDobbyProxyEvents::ContainerState::Running); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_STARTED); - EXPECT_TRUE(signalled & ON_CONTAINER_STARTED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerStarted")); -} - -/* - * Test case to verify the ON_CONTAINER_FAILED event - * This test case checks if the ON_CONTAINER_FAILED event is triggered correctly when a container fails. - * It uses a mock to simulate the container failure and verifies the event notification. - */ -TEST_F(OCIContainer_L2Test, ContainerFailedEvent_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(OCICONTAINER_CALLSIGN, OCICONTAINERTEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = OCICONTAINER_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onContainerFailed"), - &AsyncHandlerMock_OCIContainer::onContainerFailed, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"containerId\":\"com.bskyb.epgui\",\"name\":\"com.bskyb.epgui\",\"error\":1}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onContainerFailed(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &OCIContainer_L2Test::onContainerFailed)); - - EXPECT_CALL(*p_dobbyProxyMock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(true)); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - // manually trigger the state change event for the container - // as the mock does not trigger it - this->triggerOmiErrorEvent("com.bskyb.epgui", omi::IOmiProxy::ErrorType::verityFailed); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, ON_CONTAINER_FAILED); - EXPECT_TRUE(signalled & ON_CONTAINER_FAILED); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onContainerFailed")); -} - -/* - * Test case to check the error case for GetContainerState API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, GetContainerState_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - ContainerState state; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillRepeatedly(::testing::Return(containerslist)); - - status = m_OCIContainerplugin->GetContainerState(containerID, state, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("GetContainerState returned state: %d, success: %d, errorReason: %s", state, success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for GetContainerInfo API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, GetContainerInfo_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string info, errorReason; - bool success = true; - - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, getContainerInfo(91)) - .WillOnce(::testing::Return("")); - - status = m_OCIContainerplugin->GetContainerInfo(containerID, info, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("GetContainerInfo returned info: %s, success: %d, errorReason: %s", info.c_str(), success, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for StartContainer API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, StartContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui", bundlepath = "/containers/myBundle", command = "command", westerOSSocket = "/usr/mySocket"; - int32_t descriptor = 0; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromBundle(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(-1)); - - status = m_OCIContainerplugin->StartContainer(containerID, bundlepath, command, westerOSSocket, descriptor, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("StartContainer returned descriptor: %d, errorReason: %s", descriptor, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for StartContainerFromDobbySpec API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, StartContainerFromDobbySpecErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notify; - string containerID = "com.bskyb.epgui", dobbySpec = "/containers/dobbySpec", command = "command", westerOSSocket = "/usr/mySocket"; - int32_t descriptor = 0; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - EXPECT_CALL(*p_dobbyProxyMock, startContainerFromSpec(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(-1)); - - status = m_OCIContainerplugin->StartContainerFromDobbySpec(containerID, dobbySpec, command, westerOSSocket, descriptor, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("StartContainerFromDobbySpec returned descriptor: %d, errorReason: %s", descriptor, errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for StopContainer API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, StopContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - bool force = true; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, stopContainer(91, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->StopContainer(containerID, force, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("StopContainer returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for PauseContainer and ResumeContainer APIs in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, PauseContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, pauseContainer(91)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->PauseContainer(containerID, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("PauseContainer returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for ResumeContainer API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, ResumeContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, resumeContainer(91)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->ResumeContainer(containerID, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("ResumeContainer returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for HibernateContainer and WakeupContainer APIs in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, HibernateContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, options; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, hibernateContainer(91, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->HibernateContainer(containerID, options, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("HibernateContainer returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for WakeupContainer API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, WakeupContainer_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, wakeupContainer(91)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->WakeupContainer(containerID, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("WakeupContainer returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for ExecuteCommand API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, ExecuteCommand_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, options, command; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, execInContainer(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->ExecuteCommand(containerID, options, command, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("ExecuteCommand returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for Annotate API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, Annotate_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, key, value; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addAnnotation(91, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->Annotate(containerID, key, value, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("Annotate returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for RemoveAnnotation API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, RemoveAnnotation_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, key; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeAnnotation(91, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->RemoveAnnotation(containerID, key, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("RemoveAnnotation returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for Mount and Unmount APIs in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, Mount_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, source, target, type, options; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, addContainerMount(91, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->Mount(containerID, source, target, type, options, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("Mount returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} - -/* - * Test case to check the error case for Unmount API in OCIContainer plugin. - * Checks the success param and print the error reason. - */ -TEST_F(OCIContainer_L2Test, Unmount_ErrorCase) -{ - uint32_t status = Core::ERROR_GENERAL; - string containerID = "com.bskyb.epgui"; - string errorReason, target; - bool success = true; - if (CreateOCIContainerInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid OCIContainer_Client"); - } else { - EXPECT_TRUE(m_controller_OCIcontainer != nullptr); - if (m_controller_OCIcontainer) { - EXPECT_TRUE(m_OCIContainerplugin != nullptr); - if (m_OCIContainerplugin) { - m_OCIContainerplugin->AddRef(); - - std::list> containerslist = { { 91, "com.bskyb.epgui" }, { 94, "Netflix" } }; - EXPECT_CALL(*p_dobbyProxyMock, listContainers()) - .WillOnce(::testing::Return(containerslist)); - - EXPECT_CALL(*p_dobbyProxyMock, removeContainerMount(91, ::testing::_)) - .WillOnce(::testing::Return(false)); - - status = m_OCIContainerplugin->Unmount(containerID, target, success, errorReason); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_FALSE(success); - TEST_LOG("Unmount returned ContainerID: %s, errorReason: %s", containerID.c_str(), errorReason.c_str()); - - m_OCIContainerplugin->Release(); - } else { - TEST_LOG("m_OCIContainerplugin is NULL"); - } - m_controller_OCIcontainer->Release(); - } else { - TEST_LOG("m_controller_OCIcontainer is NULL"); - } - } -} diff --git a/Tests/L2Tests/tests/ResourceManager_L2Test.cpp b/Tests/L2Tests/tests/ResourceManager_L2Test.cpp deleted file mode 100644 index c1ba1be..0000000 --- a/Tests/L2Tests/tests/ResourceManager_L2Test.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include - -using namespace WPEFramework; -using ::testing::NiceMock; -using ::testing::StrictMock; - -#define RESOURCEMANAGER_CALLSIGN _T("org.rdk.ResourceManager") -#define RESOURCEMANAGERL2TEST_CALLSIGN _T("L2tests.1") -#define JSON_TIMEOUT (1000) - -class ResourceManagerTest : public L2TestMocks { -protected: - virtual ~ResourceManagerTest() override { - std::cout << "ResourceManagerTest destructor called" << std::endl; - uint32_t status = Core::ERROR_GENERAL; - status = DeactivateService("org.rdk.ResourceManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - } -public: - ResourceManagerTest() { - std::cout << "ResourceManagerTest constructor called" << std::endl; - - ON_CALL(*p_essRMgrMock, EssRMgrAddToBlackList(::testing::_, ::testing::_)) - .WillByDefault(::testing::Return(true)); - uint32_t status = Core::ERROR_GENERAL; - status = ActivateService("org.rdk.ResourceManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - } -}; -/******************************************************** -************Test case Details ************************** -** 1. Test setAVBlockedWrapper success scenario -*******************************************************/ -TEST_F(ResourceManagerTest, SetAVBlockedSuccessCase) -{ - std::cout << "SetAVBlockedSuccessCase test started" << std::endl; - JSONRPC::LinkType jsonrpc(RESOURCEMANAGER_CALLSIGN, _T("L2tests.1")); - uint32_t status = Core::ERROR_GENERAL; - JsonObject resultJson; - std::string appid = "com.example.myapp"; - bool blocked = true; - - JsonObject params; - params["appid"] = appid; - params["blocked"] = blocked; - - status = InvokeServiceMethod("org.rdk.ResourceManager", "setAVBlocked", params, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - ASSERT_TRUE(resultJson.HasLabel("success")); - EXPECT_TRUE(resultJson["success"].Boolean()); - std::cout << "SetAVBlockedSuccessCase test finished" << std::endl; -} -/******************************************************** -************Test case Details ************************** -** Negative test: setAVBlockedWrapper missing required parameters -*******************************************************/ -TEST_F(ResourceManagerTest, SetAVBlockedMissingParams) -{ - std::cout << "SetAVBlockedMissingParams test started" << std::endl; - JsonObject resultJson; - JsonObject params; - uint32_t status = InvokeServiceMethod("org.rdk.ResourceManager", "setAVBlocked", params, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - ASSERT_TRUE(resultJson.HasLabel("success")); - EXPECT_TRUE(resultJson["success"].Boolean()); - std::cout << "SetAVBlockedMissingParams test finished" << std::endl; -} -/******************************************************** -************Test case Details ************************** -** 1. Test getBlockedAVApplicationsWrapper success scenario -*******************************************************/ -TEST_F(ResourceManagerTest, GetBlockedAVApplicationsSuccessCase) -{ - std::cout << "GetBlockedAVApplicationsSuccessCase test started" << std::endl; - JSONRPC::LinkType jsonrpc(RESOURCEMANAGER_CALLSIGN, RESOURCEMANAGERL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - // First, block the app 'org.rdk.Netflix' - JsonObject setParams; - setParams["appid"] = "org.rdk.Netflix"; - setParams["blocked"] = true; - JsonObject setResult; - status = InvokeServiceMethod("org.rdk.ResourceManager", "setAVBlocked", setParams, setResult); - EXPECT_EQ(status, Core::ERROR_NONE); - ASSERT_TRUE(setResult.HasLabel("success")); - EXPECT_TRUE(setResult["success"].Boolean()); - - // Now, get the blocked apps - JsonObject resultJson; - JsonObject params; - status = InvokeServiceMethod("org.rdk.ResourceManager", "getBlockedAVApplications", params, resultJson); - EXPECT_EQ(status, Core::ERROR_NONE); - ASSERT_TRUE(resultJson.HasLabel("success")); - EXPECT_TRUE(resultJson["success"].Boolean()); - ASSERT_TRUE(resultJson.HasLabel("clients")); - const JsonArray& clients = resultJson["clients"].Array(); - bool found = false; - for (size_t i = 0; i < clients.Length(); ++i) { - if (clients[i].String() == "org.rdk.Netflix") { - found = true; - break; - } - } - EXPECT_TRUE(found); - std::cout << "GetBlockedAVApplicationsSuccessCase test finished" << std::endl; -} -/******************************************************** -************Test case Details ************************** -** 1. Test reserveTTSResourceWrapper -*******************************************************/ -TEST_F(ResourceManagerTest, ReserveTTSResourceTest) -{ - std::cout << "ReserveTTSResourceTest test started" << std::endl; - JsonObject resultJson; - std::string appid = "xumo"; - JsonObject params; - params["appid"] = appid; - uint32_t status = InvokeServiceMethod("org.rdk.ResourceManager", "reserveTTSResource", params, resultJson); - - EXPECT_NE(status, Core::ERROR_NONE); - EXPECT_FALSE(resultJson.HasLabel("success")); - std::cout << "ReserveTTSResourceTest test finished" << std::endl; -} - -/******************************************************** -************Test case Details ************************** -** 1. Test reserveTTSResourceForApps with 'appids' parameter -*******************************************************/ -TEST_F(ResourceManagerTest, ReserveTTSResourceForApps) -{ - std::cout << "ReserveTTSResourceForApps test started" << std::endl; - JsonObject resultJson; - JsonArray appids; - appids.Add(JsonValue("xumo")); - appids.Add(JsonValue("netflix")); - JsonObject params; - params["appids"] = appids; - uint32_t status = InvokeServiceMethod("org.rdk.ResourceManager", "reserveTTSResourceForApps", params, resultJson); - EXPECT_NE(status, Core::ERROR_NONE); - EXPECT_FALSE(resultJson.HasLabel("success")); - std::cout << "ReserveTTSResourceForApps test finished" << std::endl; -} - diff --git a/Tests/L2Tests/tests/SharedStorage_L2Test.cpp b/Tests/L2Tests/tests/SharedStorage_L2Test.cpp deleted file mode 100644 index 883ccdf..0000000 --- a/Tests/L2Tests/tests/SharedStorage_L2Test.cpp +++ /dev/null @@ -1,1274 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "SecureStorageServerMock.h" -#include "SecureStorageServiceMock.h" - -#define EVNT_TIMEOUT (1000) -#define SHAREDSTORAGE_CALLSIGN _T("org.rdk.SharedStorage.1") -#define SHAREDSTORAGETEST_CALLSIGN _T("L2tests.1") - -#define TEST_LOG(x, ...) \ - fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); \ - fflush(stderr); - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::ISharedStorage; -using ::WPEFramework::Exchange::ISharedStorageCache; -using ::WPEFramework::Exchange::ISharedStorageInspector; -using ::WPEFramework::Exchange::ISharedStorageLimit; -using ScopeType = WPEFramework::Exchange::ISharedStorage::ScopeType; -using Success = WPEFramework::Exchange::ISharedStorage::Success; - -typedef enum : uint32_t { - - SHARED_STORAGE_ON_VALUE_CHANGED = 0x00000001, - SHARED_STORAGE_STATUS_INVALID = 0x00000000 - -} SharedStorageL2test_async_events_t; - -class AsyncHandlerMock_SharedStorage { -public: - AsyncHandlerMock_SharedStorage() - { - } - MOCK_METHOD(void, onValueChanged, (const JsonObject& message)); -}; - -// SharedStorage and CloudStore Notification Handler Class -class SharedStorageNotificationHandler : public Exchange::ISharedStorage::INotification { -private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::ISharedStorage::INotification) - END_INTERFACE_MAP - -public: - SharedStorageNotificationHandler() {} - ~SharedStorageNotificationHandler() {} - - // Shared Store notification - void OnValueChanged(const ScopeType scope, const string& ns, const string& key, const string& value) - { - TEST_LOG("OnValueChanged event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnValueChanged received (SCOPE): %s\n", scope == ScopeType::DEVICE ? "DEVICE" : "ACCOUNT"); - TEST_LOG("OnValueChanged received (NAMESPACE): %s\n", ns.c_str()); - TEST_LOG("OnValueChanged received (KEY): %s\n", key.c_str()); - TEST_LOG("OnValueChanged received (VALUE): %s\n", value.c_str()); - /* Notify the requester thread. */ - m_event_signalled |= SHARED_STORAGE_ON_VALUE_CHANGED; - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, SharedStorageL2test_async_events_t expected_status) - { - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - - while (!(expected_status & m_event_signalled)) { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; - } -}; - -class SharedStorage_L2test : public L2TestMocks { -protected: - virtual ~SharedStorage_L2test() override; - SharedStorage_L2test(); - -public: - void onValueChanged(const JsonObject& message); - uint32_t WaitForRequestStatus(uint32_t timeout_ms, SharedStorageL2test_async_events_t expected_status); - uint32_t CreateSharedStorageInterfaceObject(); - -private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - -protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell* m_controller_sharedstorage; - - /** @brief Pointer to the ISharedStorage interface */ - Exchange::ISharedStorage* m_sharedstorageplugin; - - std::unique_ptr mock_server; - - // start the mock server before the plugin is activated - void SetUp() override - { - auto service = std::make_unique>(); - mock_server = std::make_unique(std::move(service), "0.0.0.0:50051"); - - uint32_t status = Core::ERROR_GENERAL; - status = ActivateService("org.rdk.CloudStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = ActivateService("org.rdk.SharedStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); - } - - SecureStorageServiceMock* GetMock() { return mock_server->GetMock(); } -}; - -SharedStorage_L2test::SharedStorage_L2test() - : L2TestMocks() -{ - uint32_t status = Core::ERROR_GENERAL; - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -SharedStorage_L2test::~SharedStorage_L2test() -{ - TEST_LOG("Inside SharedStorage_L2test destructor"); - - uint32_t status = Core::ERROR_GENERAL; - - /* Deactivate plugin in destructor */ - status = DeactivateService("org.rdk.CloudStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = DeactivateService("org.rdk.SharedStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = DeactivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - - if (mock_server) { - mock_server.reset(); - std::this_thread::sleep_for(std::chrono::seconds(5)); // Wait for the mock server to properly shutdown - } -} - -uint32_t SharedStorage_L2test::CreateSharedStorageInterfaceObject() -{ - uint32_t return_value = Core::ERROR_GENERAL; - Core::ProxyType> SharedStorage_Engine; - Core::ProxyType SharedStorage_Client; - - TEST_LOG("Creating SharedStorage_Engine"); - SharedStorage_Engine = Core::ProxyType>::Create(); - SharedStorage_Client = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(SharedStorage_Engine)); - - TEST_LOG("Creating SharedStorage_Engine Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - SharedStorage_Engine->Announcements(mSharedStorage_Client->Announcement()); -#endif - if (!SharedStorage_Client.IsValid()) { - TEST_LOG("Invalid SharedStorage_Client"); - } else { - m_controller_sharedstorage = SharedStorage_Client->Open(_T("org.rdk.SharedStorage"), ~0, 3000); - if (m_controller_sharedstorage) { - m_sharedstorageplugin = m_controller_sharedstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -class SharedStorage_L2testDeviceScope : public L2TestMocks { -protected: - virtual ~SharedStorage_L2testDeviceScope() override; - SharedStorage_L2testDeviceScope(); - -public: - void onValueChanged(const JsonObject& message); - uint32_t WaitForRequestStatus(uint32_t timeout_ms, SharedStorageL2test_async_events_t expected_status); - uint32_t CreateSharedStorageInterfaceObject(int interface); - -private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - -protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell* m_controller_sharedstorage; - - /** @brief Pointer to the ISharedStorage interface */ - Exchange::ISharedStorage* m_sharedstorageplugin; - - /** @brief Pointer to the ISharedStorageInspector interface */ - Exchange::ISharedStorageInspector* m_sharedstorageinspectorplugin; - - /** @brief Pointer to the ISharedStorageLimit interface */ - Exchange::ISharedStorageLimit* m_sharedstoragelimitplugin; - - /** @brief Pointer to the ISharedStorageCache interface */ - Exchange::ISharedStorageCache* m_sharedstoragecacheplugin; -}; - -SharedStorage_L2testDeviceScope::SharedStorage_L2testDeviceScope() - : L2TestMocks() -{ - uint32_t status = Core::ERROR_GENERAL; - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = ActivateService("org.rdk.SharedStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -SharedStorage_L2testDeviceScope::~SharedStorage_L2testDeviceScope() -{ - TEST_LOG("Inside SharedStorage_L2testDeviceScope destructor"); - - uint32_t status = Core::ERROR_GENERAL; - - /* Deactivate plugin in destructor */ - status = DeactivateService("org.rdk.SharedStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = DeactivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -uint32_t SharedStorage_L2testDeviceScope::CreateSharedStorageInterfaceObject(int interface) -{ - uint32_t return_value = Core::ERROR_GENERAL; - Core::ProxyType> SharedStorage_Engine; - Core::ProxyType SharedStorage_Client; - - TEST_LOG("Creating SharedStorage_Engine"); - SharedStorage_Engine = Core::ProxyType>::Create(); - SharedStorage_Client = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(SharedStorage_Engine)); - - TEST_LOG("Creating SharedStorage_Engine Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - SharedStorage_Engine->Announcements(mSharedStorage_Client->Announcement()); -#endif - if (!SharedStorage_Client.IsValid()) { - TEST_LOG("Invalid SharedStorage_Client"); - } else { - m_controller_sharedstorage = SharedStorage_Client->Open(_T("org.rdk.SharedStorage"), ~0, 3000); - if (m_controller_sharedstorage) { - if (interface == 0) { - m_sharedstorageplugin = m_controller_sharedstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } else if (interface == 1) { - m_sharedstorageinspectorplugin = m_controller_sharedstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } else if (interface == 2) { - m_sharedstoragelimitplugin = m_controller_sharedstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } else if (interface == 3) { - m_sharedstoragecacheplugin = m_controller_sharedstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - } - return return_value; -} - -uint32_t SharedStorage_L2test::WaitForRequestStatus(uint32_t timeout_ms, SharedStorageL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - - while (!(expected_status & m_event_signalled)) { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void SharedStorage_L2test::onValueChanged(const JsonObject& message) -{ - TEST_LOG("OnValueChanged event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - message.ToString(str); - - TEST_LOG("OnValueChanged received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= SHARED_STORAGE_ON_VALUE_CHANGED; - m_condition_variable.notify_one(); -} - -uint32_t SharedStorage_L2testDeviceScope::WaitForRequestStatus(uint32_t timeout_ms, SharedStorageL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - - while (!(expected_status & m_event_signalled)) { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void SharedStorage_L2testDeviceScope::onValueChanged(const JsonObject& message) -{ - TEST_LOG("OnValueChanged event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - message.ToString(str); - - TEST_LOG("OnValueChanged received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= SHARED_STORAGE_ON_VALUE_CHANGED; - m_condition_variable.notify_one(); -} - -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s", expected.c_str(), actual.c_str()); - EXPECT_STREQ(expected.c_str(), actual.c_str()); - - return match; -} - -/* - * Test case to test the SetValue method of SharedStorage plugin with scope set as ACCOUNT using JSONRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - * The test case also checks that the OnValueChanged notification is triggered with the correct - * parameters. - */ - -TEST_F(SharedStorage_L2test, SetValue_ACCOUNT_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onValueChanged"), - &AsyncHandlerMock_SharedStorage::onValueChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"scope\":\"account\",\"namespace\":\"ns1\",\"key\":\"key1\",\"value\":\"value1\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onValueChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &SharedStorage_L2test::onValueChanged)); - - EXPECT_CALL(*GetMock(), UpdateValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(testing::Invoke([](::grpc::ServerContext*, - const distp::gateway::secure_storage::v1::UpdateValueRequest* request, - distp::gateway::secure_storage::v1::UpdateValueResponse* response) { - EXPECT_EQ(request->value().value(), "value1"); - EXPECT_EQ(request->value().key().key(), "key1"); - EXPECT_EQ(request->value().key().app_id(), "ns1"); - EXPECT_EQ(request->value().key().scope(), distp::gateway::secure_storage::v1::SCOPE_ACCOUNT); - return grpc::Status::OK; - })); - - JsonObject params, result; - params["namespace"] = "ns1"; - params["key"] = "key1"; - params["value"] = "value1"; - params["scope"] = "account"; - params["ttl"] = 60; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "setValue", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, SHARED_STORAGE_ON_VALUE_CHANGED); - EXPECT_TRUE(signalled & SHARED_STORAGE_ON_VALUE_CHANGED); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onValueChanged")); -} - -/* - * Test case to test the GetValue method of SharedStorage plugin with scope set as ACCOUNT using JSONRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, GetValue_ACCOUNT_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - EXPECT_CALL(*GetMock(), GetValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [](grpc::ServerContext*, - const distp::gateway::secure_storage::v1::GetValueRequest* request, - distp::gateway::secure_storage::v1::GetValueResponse* response) { - EXPECT_EQ(request->key().key(), "key1"); - EXPECT_EQ(request->key().app_id(), "ns1"); - EXPECT_EQ(request->key().scope(), distp::gateway::secure_storage::v1::SCOPE_ACCOUNT); - - auto* value = new distp::gateway::secure_storage::v1::Value(); - value->set_value("value1"); - auto* ttl = new google::protobuf::Duration(); - ttl->set_seconds(60); - value->set_allocated_ttl(ttl); - auto* key = new distp::gateway::secure_storage::v1::Key(); - key->set_key(request->key().key()); - key->set_app_id(request->key().app_id()); - key->set_scope(request->key().scope()); - value->set_allocated_key(key); - response->set_allocated_value(value); - return grpc::Status::OK; - })); - - JsonObject params, result; - params["scope"] = "ACCOUNT"; - params["namespace"] = "ns1"; - params["key"] = "key1"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getValue", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_EQ(result["value"], "value1"); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the DeleteKey method of SharedStorage plugin with scope set as ACCOUNT using JSONRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, deleteKey_ACCOUNT_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - EXPECT_CALL(*GetMock(), DeleteValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](::grpc::ServerContext* context, - const distp::gateway::secure_storage::v1::DeleteValueRequest* request, - distp::gateway::secure_storage::v1::DeleteValueResponse* response) { - return grpc::Status::OK; - })); - - JsonObject params, result; - params["namespace"] = "ns1"; - params["key"] = "key1"; - params["scope"] = "ACCOUNT"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "deleteKey", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the DeleteNamespace method of SharedStorage plugin with scope set as ACCOUNT using JSONRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, deleteNamespace_ACCOUNT_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - EXPECT_CALL(*GetMock(), DeleteAllValues(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [](grpc::ServerContext* context, - const distp::gateway::secure_storage::v1::DeleteAllValuesRequest* request, - distp::gateway::secure_storage::v1::DeleteAllValuesResponse* response) { - EXPECT_EQ(request->scope(), distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT); - EXPECT_EQ(request->app_id(), "ns1"); - return grpc::Status::OK; - })); - - JsonObject params, result; - params["namespace"] = "ns1"; - params["scope"] = "ACCOUNT"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "deleteNamespace", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the SetValue method of SharedStorage plugin with scope set as DEVICE using JSONRPC. - * The test case also checks that the OnValueChanged notification is triggered with the correct - * parameters. - */ -TEST_F(SharedStorage_L2testDeviceScope, SetValue_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - StrictMock async_handler; - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - uint32_t status = Core::ERROR_GENERAL; - std::string message; - JsonObject expected_status; - - status = jsonrpc.Subscribe(EVNT_TIMEOUT, - _T("onValueChanged"), - &AsyncHandlerMock_SharedStorage::onValueChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - message = "{\"scope\":\"device\",\"namespace\":\"ns1\",\"key\":\"key1\",\"value\":\"value1\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onValueChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &SharedStorage_L2testDeviceScope::onValueChanged)); - - JsonObject params, result; - params["namespace"] = "ns1"; - params["key"] = "key1"; - params["value"] = "value1"; - params["scope"] = "device"; - params["ttl"] = 100; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "setValue", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - - signalled = WaitForRequestStatus(EVNT_TIMEOUT, SHARED_STORAGE_ON_VALUE_CHANGED); - EXPECT_TRUE(signalled & SHARED_STORAGE_ON_VALUE_CHANGED); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - jsonrpc.Unsubscribe(EVNT_TIMEOUT, _T("onValueChanged")); -} - -/* - * Test case to test the GetValue method of SharedStorage plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetValue_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["scope"] = "device"; - params["namespace"] = "ns1"; - params["key"] = "key1"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getValue", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); - sleep(5); - int file_status = remove("/tmp/secure/persistent/rdkservicestore"); - // Check if the file has been successfully removed - if (file_status != 0) { - TEST_LOG("Error deleting file[/tmp/secure/persistent/rdkservicestore]"); - } else { - TEST_LOG("File[/tmp/secure/persistent/rdkservicestore] successfully deleted"); - } -} - -/* - * Test case to test the DeleteKey method of SharedStorage plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, deleteKey_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["namespace"] = "ns1"; - params["key"] = "key1"; - params["scope"] = "device"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "deleteKey", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the DeleteNamespace method of SharedStorage plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, deleteNamespace_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["namespace"] = "ns1"; - params["scope"] = "device"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "deleteNamespace", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the SetValue method of SharedStorage plugin with scope set as ACCOUNT using COMRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - * The test case also checks that the OnValueChanged notification is triggered with the correct - * parameters. - */ -TEST_F(SharedStorage_L2test, SetValue_ACCOUNT_Scope_COMRPC) -{ - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - Core::Sink notify; - uint32_t status = Core::ERROR_GENERAL; - const auto kKey = "key1"; - const auto kValue = "value1"; - const auto kAppId = "ns1"; - const auto kTtl = 60; - Success result; - - if (CreateSharedStorageInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - m_sharedstorageplugin->Register(¬ify); - - EXPECT_CALL(*GetMock(), UpdateValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(testing::Invoke([](::grpc::ServerContext*, - const distp::gateway::secure_storage::v1::UpdateValueRequest* request, - distp::gateway::secure_storage::v1::UpdateValueResponse* response) { - EXPECT_EQ(request->value().value(), "value1"); - EXPECT_EQ(request->value().key().key(), "key1"); - EXPECT_EQ(request->value().key().app_id(), "ns1"); - EXPECT_EQ(request->value().key().scope(), distp::gateway::secure_storage::v1::SCOPE_ACCOUNT); - return grpc::Status::OK; - })); - - status = m_sharedstorageplugin->SetValue(ScopeType::ACCOUNT, kAppId, kKey, kValue, kTtl, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, SHARED_STORAGE_ON_VALUE_CHANGED); - EXPECT_TRUE(signalled & SHARED_STORAGE_ON_VALUE_CHANGED); - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - m_sharedstorageplugin->Unregister(¬ify); - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the GetValue method of SharedStorage plugin with scope set as ACCOUNT using COMRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, GetValue_ACCOUNT_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - string value; - uint32_t ttl; - bool success = false; - if (CreateSharedStorageInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - EXPECT_CALL(*GetMock(), GetValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [](grpc::ServerContext*, - const distp::gateway::secure_storage::v1::GetValueRequest* request, - distp::gateway::secure_storage::v1::GetValueResponse* response) { - EXPECT_EQ(request->key().key(), "key1"); - EXPECT_EQ(request->key().app_id(), "ns1"); - EXPECT_EQ(request->key().scope(), distp::gateway::secure_storage::v1::SCOPE_ACCOUNT); - - auto* value = new distp::gateway::secure_storage::v1::Value(); - value->set_value("mocked_value"); - auto* ttl = new google::protobuf::Duration(); - ttl->set_seconds(60); - value->set_allocated_ttl(ttl); - auto* key = new distp::gateway::secure_storage::v1::Key(); - key->set_key(request->key().key()); - key->set_app_id(request->key().app_id()); - key->set_scope(request->key().scope()); - value->set_allocated_key(key); - response->set_allocated_value(value); - return grpc::Status::OK; - })); - - status = m_sharedstorageplugin->GetValue(ScopeType::ACCOUNT, "ns1", "key1", value, ttl, success); - EXPECT_EQ(status, Core::ERROR_NONE); - TEST_LOG("GetValue returned value: %s, ttl: %u, success: %d", value.c_str(), ttl, success); - EXPECT_TRUE(success); - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the DeleteKey method of SharedStorage plugin with scope set as ACCOUNT using COMRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, DeleteKey_ACCOUNT_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Success result; - - if (CreateSharedStorageInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - EXPECT_CALL(*GetMock(), DeleteValue(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](::grpc::ServerContext* context, - const distp::gateway::secure_storage::v1::DeleteValueRequest* request, - distp::gateway::secure_storage::v1::DeleteValueResponse* response) { - return grpc::Status::OK; - })); - - status = m_sharedstorageplugin->DeleteKey(ScopeType::ACCOUNT, "namespace", "key", result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* * Test case to test the DeleteNamespace method of SharedStorage plugin with scope set as ACCOUNT using COMRPC. - * This test case uses a mock gRPC server to simulate the behavior of the SecureStorageService. - */ -TEST_F(SharedStorage_L2test, DeleteNamespace_ACCOUNT_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - Success result; - - if (CreateSharedStorageInterfaceObject() != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - EXPECT_CALL(*GetMock(), DeleteAllValues(::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [](grpc::ServerContext* context, - const distp::gateway::secure_storage::v1::DeleteAllValuesRequest* request, - distp::gateway::secure_storage::v1::DeleteAllValuesResponse* response) { - EXPECT_EQ(request->scope(), distp::gateway::secure_storage::v1::Scope::SCOPE_ACCOUNT); - EXPECT_EQ(request->app_id(), "ns1"); - return grpc::Status::OK; - })); - - status = m_sharedstorageplugin->DeleteNamespace(ScopeType::ACCOUNT, "ns1", result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the SetValue method of SharedStorage plugin with scope set as Device using COMRPC. - * The test case also checks that the OnValueChanged notification is triggered with the correct - * parameters. - */ -TEST_F(SharedStorage_L2testDeviceScope, SetValue_DEVICE_Scope_COMRPC) -{ - uint32_t signalled = SHARED_STORAGE_STATUS_INVALID; - Core::Sink notify; - uint32_t status = Core::ERROR_GENERAL; - int interface = 0; // 0 for ISharedStorage - const auto kKey = "key1"; - const auto kValue = "value1"; - const auto kAppId = "ns1"; - const auto kTtl = 60; - Success result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - m_sharedstorageplugin->Register(¬ify); - - status = m_sharedstorageplugin->SetValue(ScopeType::DEVICE, kAppId, kKey, kValue, kTtl, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - signalled = notify.WaitForRequestStatus(EVNT_TIMEOUT, SHARED_STORAGE_ON_VALUE_CHANGED); - EXPECT_TRUE(signalled & SHARED_STORAGE_ON_VALUE_CHANGED); - - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - m_sharedstorageplugin->Unregister(¬ify); - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the GetValue method of SharedStorage plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetValue_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 0; // 0 for ISharedStorage - string value; - uint32_t ttl; - bool success = false; - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - status = m_sharedstorageplugin->GetValue(ScopeType::DEVICE, "ns1", "key1", value, ttl, success); - EXPECT_EQ(status, Core::ERROR_NONE); - TEST_LOG("GetValue returned value: %s, ttl: %u, success: %d", value.c_str(), ttl, success); - EXPECT_TRUE(success); - - sleep(5); - int file_status = remove("/tmp/secure/persistent/rdkservicestore"); - // Check if the file has been successfully removed - if (file_status != 0) { - TEST_LOG("Error deleting file[/tmp/secure/persistent/rdkservicestore]"); - } else { - TEST_LOG("File[/tmp/secure/persistent/rdkservicestore] successfully deleted"); - } - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the DeleteKey method of SharedStorage plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, DeleteKey_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 0; // 0 for ISharedStorage - Success result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - status = m_sharedstorageplugin->DeleteKey(ScopeType::DEVICE, "ns1", "key1", result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the DeleteNamespace method of SharedStorage plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, DeleteNamespace_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 0; // 0 for ISharedStorage - Success result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageplugin != nullptr); - if (m_sharedstorageplugin) { - m_sharedstorageplugin->AddRef(); - - status = m_sharedstorageplugin->DeleteNamespace(ScopeType::DEVICE, "ns1", result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result.success); - - m_sharedstorageplugin->Release(); - } else { - TEST_LOG("m_sharedstorageplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test cases to test the GetKeys method of SharedStorageInspector plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetKeys_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 1; // 1 for ISharedStorageInspector - Exchange::ISharedStorageInspector::IStringIterator* keys = nullptr; - bool result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageinspectorplugin != nullptr); - if (m_sharedstorageinspectorplugin) { - m_sharedstorageinspectorplugin->AddRef(); - - status = m_sharedstorageinspectorplugin->GetKeys(ScopeType::DEVICE, "ns1", keys, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result); - // print the keys - if (keys != nullptr) { - std::string key; - while (keys->Next(key)) { - TEST_LOG("Key: %s", key.c_str()); - } - keys->Release(); - } - - m_sharedstorageinspectorplugin->Release(); - } else { - TEST_LOG("m_sharedstorageinspectorplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the GetNamespaces method of SharedStorageInspector plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetNamespaces_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 1; // 1 for ISharedStorageInspector - Exchange::ISharedStorageInspector::IStringIterator* namespaces = nullptr; - bool result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageinspectorplugin != nullptr); - if (m_sharedstorageinspectorplugin) { - m_sharedstorageinspectorplugin->AddRef(); - - status = m_sharedstorageinspectorplugin->GetNamespaces(ScopeType::DEVICE, namespaces, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result); - // print the namespaces - if (namespaces != nullptr) { - std::string ns; - while (namespaces->Next(ns)) { - TEST_LOG("Namespace: %s", ns.c_str()); - } - namespaces->Release(); - } - - m_sharedstorageinspectorplugin->Release(); - } else { - TEST_LOG("m_sharedstorageinspectorplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the GetStorageSizes method of SharedStorageInspector plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetStorageSizes_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 1; // 1 for ISharedStorageInspector - Exchange::ISharedStorageInspector::INamespaceSizeIterator* storagelist = nullptr; - bool result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstorageinspectorplugin != nullptr); - if (m_sharedstorageinspectorplugin) { - m_sharedstorageinspectorplugin->AddRef(); - - status = m_sharedstorageinspectorplugin->GetStorageSizes(ScopeType::DEVICE, storagelist, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result); - Exchange::ISharedStorageInspector::NamespaceSize nsSize{}; - while (storagelist->Next(nsSize)) { - TEST_LOG("Namespace: %s, Size: %u bytes", nsSize.ns.c_str(), nsSize.size); - } - storagelist->Release(); - - m_sharedstorageinspectorplugin->Release(); - } else { - TEST_LOG("m_sharedstorageinspectorplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the SetNamespaceStorageLimit and GetNamespaceStorageLimit method of SharedStorageLimit plugin with scope set as DEVICE using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, Set_GetNamespaceStorageLimit_DEVICE_Scope_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 2; // 2 for ISharedStorageLimit - Exchange::ISharedStorageLimit::StorageLimit Limit; - uint32_t limit = 100; - bool result; - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstoragelimitplugin != nullptr); - if (m_sharedstoragelimitplugin) { - m_sharedstoragelimitplugin->AddRef(); - - status = m_sharedstoragelimitplugin->SetNamespaceStorageLimit(ScopeType::DEVICE, "ns1", limit, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result); - - status = m_sharedstoragelimitplugin->GetNamespaceStorageLimit(ScopeType::DEVICE, "ns1", Limit); - EXPECT_EQ(status, Core::ERROR_NONE); - TEST_LOG("\nStorage Limit: %u bytes\n", Limit.storageLimit); - - m_sharedstoragelimitplugin->Release(); - } else { - TEST_LOG("m_sharedstoragelimitplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test case to test the FlushCache method of SharedStorageCache plugin using COMRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, FlushCache_COMRPC) -{ - uint32_t status = Core::ERROR_GENERAL; - int interface = 3; // 3 for ISharedStorageCache - - if (CreateSharedStorageInterfaceObject(interface) != Core::ERROR_NONE) { - TEST_LOG("Invalid SharedStore_Client"); - } else { - EXPECT_TRUE(m_controller_sharedstorage != nullptr); - if (m_controller_sharedstorage) { - EXPECT_TRUE(m_sharedstoragecacheplugin != nullptr); - if (m_sharedstoragecacheplugin) { - m_sharedstoragecacheplugin->AddRef(); - - status = m_sharedstoragecacheplugin->FlushCache(); - EXPECT_EQ(status, Core::ERROR_NONE); - - m_sharedstoragecacheplugin->Release(); - } else { - TEST_LOG("m_sharedstoragecacheplugin is NULL"); - } - m_controller_sharedstorage->Release(); - } else { - TEST_LOG("m_controller_sharedstorage is NULL"); - } - } -} - -/* - * Test cases to test the GetKeys method of SharedStorageInspector plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetKeys_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["namespace"] = "ns1"; - params["scope"] = "device"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getKeys", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the GetNamespaces method of SharedStorageInspector plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetNamespaces_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["scope"] = "device"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getNamespaces", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the GetStorageSizes method of SharedStorageInspector plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, GetStorageSizes_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["scope"] = "device"; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getStorageSizes", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_TRUE(result["success"].Boolean()); -} - -/* - * Test case to test the SetNamespaceStorageLimit and GetNamespaceStorageLimit method of SharedStorageLimit plugin with scope set as DEVICE using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, Set_GetNamespaceStorageLimit_DEVICE_Scope_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - params["scope"] = "device"; - params["namespace"] = "ns1"; - params["storageLimit"] = 100; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "setNamespaceStorageLimit", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); - - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "getNamespaceStorageLimit", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); -} - -/* - * Test case to test the FlushCache method of SharedStorageCache plugin using JSONRPC. - */ -TEST_F(SharedStorage_L2testDeviceScope, FlushCache_JSONRPC) -{ - JSONRPC::LinkType jsonrpc(SHAREDSTORAGE_CALLSIGN, SHAREDSTORAGETEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - - JsonObject params, result; - status = InvokeServiceMethod("org.rdk.SharedStorage.1", "flushCache", params, result); - EXPECT_EQ(status, Core::ERROR_NONE); -} diff --git a/Tests/L2Tests/tests/StorageManager_L2Test.cpp b/Tests/L2Tests/tests/StorageManager_L2Test.cpp deleted file mode 100755 index 8f426c3..0000000 --- a/Tests/L2Tests/tests/StorageManager_L2Test.cpp +++ /dev/null @@ -1,985 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include -#include -#include -#include - - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define DEFAULT_APP_STORAGE_PATH "/tmp/persistent/storageManager" - -#define STORAGE_BLOCK_SIZE 4096; // Block size -#define STORAGE_FR_SIZE 4096; // Fragment size -#define STORAGE_TOTAL_BLOCKS 100000; // Total blocks -#define STORAGE_FREE_BLOCKS 500000; // Free blocks -#define STORAGE_AVAILABLE_BLOCKS 500000; // Available blocks - -#define JSON_TIMEOUT (1000) -#define STORAGEMANAGER_CALLSIGN _T("org.rdk.StorageManager") -#define STORAGEMANAGERL2TEST_CALLSIGN _T("L2tests.1") - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::IStorageManager; - -class StorageManagerTest : public L2TestMocks { -protected: - virtual ~StorageManagerTest() override; - -public: - StorageManagerTest(); - - uint32_t CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - void ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - - private: - - protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *mControllerStorageManager; - Core::ProxyType> mEngineStorageManager; - Core::ProxyType mClientStorageManager; - - /** @brief Pointer to the IStorageManager interface */ - Exchange::IStorageManager *mStorageManagerPlugin; -}; - -StorageManagerTest:: StorageManagerTest():L2TestMocks() -{ - Core::JSONRPC::Message message; - string response; - uint32_t status = Core::ERROR_GENERAL; - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - status = ActivateService(STORAGEMANAGER_CALLSIGN); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/** - * @brief Destructor for SystemServices L2 test class - */ -StorageManagerTest::~StorageManagerTest() -{ - uint32_t status = Core::ERROR_GENERAL; - - status = DeactivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService(STORAGEMANAGER_CALLSIGN); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -uint32_t StorageManagerTest::CreateStorageManagerInterfaceObjectUsingComRPCConnection() -{ - uint32_t return_value = Core::ERROR_GENERAL; - - TEST_LOG("Creating mEngineStorageManager"); - mEngineStorageManager = Core::ProxyType>::Create(); - mClientStorageManager = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(mEngineStorageManager)); - - TEST_LOG("Creating mEngineStorageManager Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - mEngineStorageManager->Announcements(mmClientStorageManager->Announcement()); -#endif - if (!mClientStorageManager.IsValid()) - { - TEST_LOG("Invalid mClientStorageManager"); - } - else - { - mControllerStorageManager = mClientStorageManager->Open(_T(STORAGEMANAGER_CALLSIGN), ~0, 3000); - if (mControllerStorageManager) - { - mStorageManagerPlugin = mControllerStorageManager->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -void StorageManagerTest::ReleaseStorageManagerInterfaceObjectUsingComRPCConnection() -{ - if (mStorageManagerPlugin) - { - mStorageManagerPlugin->Release(); - mStorageManagerPlugin = nullptr; - } - - if (mControllerStorageManager) - { - mControllerStorageManager->Release(); - mControllerStorageManager = nullptr; - } - - mClientStorageManager->Close(RPC::CommunicationTimeOut); - if (mClientStorageManager.IsValid()) - { - mClientStorageManager.Release(); - } - mEngineStorageManager.Release(); -} - -bool fileExists(const std::string& filename) -{ - std::ifstream file(filename); - bool fileAvailable = file.good(); - - if (fileAvailable) - { - file.close(); - } - - TEST_LOG("File Name: %s, fileAvailable: %d", filename.c_str(), fileAvailable); - return fileAvailable; -} - -void createFileAndAddContent(const std::string& filePath, const std::string& fileName, const std::string& appId, const std::string& content) -{ - std::string exampleFolder = std::string(DEFAULT_APP_STORAGE_PATH) + "/" + appId + "/example"; - - if (mkdir(exampleFolder.c_str(), 0755) != 0 && errno != EEXIST) - { - TEST_LOG("Directory creation failed"); - } - else - { - std::string fileNameWithPath = exampleFolder + "/" + fileName; - std::ofstream outFile(fileNameWithPath); - - if (!outFile) - { - TEST_LOG("File creation failed"); - } - else - { - outFile << content; - TEST_LOG("File created: %s", fileNameWithPath.c_str()); - - outFile.close(); - } - } -} - -/* Test Case for CreateGetAndDeleteStorageUsingComRpcSuccess - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() and statvfs() system calls to simulate filesystem availability and space - * Calling CreateStorage() with valid appId and size, verifying success and expected storage path - * Setting Mock for chown() to simulate ownership change on created storage path - * Calling GetStorage() with appId and verifying retrieved storage path, size, and used space - * Calling DeleteStorage() and verifying successful deletion of the storage - * Verifying GetStorage() returns error after deletion, as storage no longer exists - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, CreateGetAndDeleteStorageUsingComRpcSuccess) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - std::string actualPath = ""; - uint32_t actualSize = 0; - uint32_t actualUsed = 0; - std::string expectedPath = ""; - - TEST_LOG("### Test CreateGetAndDeleteStorageUsingComRpcSuccess Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - expectedPath = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId; - - EXPECT_CALL(*p_wrapsImplMock, chown(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char *path, uid_t owner, gid_t group) -> int { - // Simulate success - TEST_LOG("### p_wrapsImplMock chown ###"); - return 0; - }); - - /* Verifing GetStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->GetStorage(appId, 1000, 1001, actualPath, actualSize, actualUsed)); - TEST_LOG("GetStorage_Success actualPath = %s actualSize: %u used: %u",actualPath.c_str(), actualSize, actualUsed); - - EXPECT_STREQ(expectedPath.c_str(), actualPath.c_str()); - EXPECT_EQ(size, actualSize); - EXPECT_EQ(0U, actualUsed); - - /* Verify DeleteStorage will success */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - /* Verify GetStorage will fail, it should return Core::ERROR_GENERAL as already deleted the storage */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->GetStorage(appId, 1000, 1001, actualPath, actualSize, actualUsed)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test CreateGetAndDeleteStorageUsingComRpcSuccess End ###"); -} - -/* Test Case for CreateStorageUsingComRpcSuccessExistingIfStorageNotAccessiable - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for statvfs() system call to simulate available disk space - * Calling CreateStorage() to create new storage for given appId - * Simulating access() failure (storage path not accessible) for existing path - * Re-calling CreateStorage() to verify it handles inaccessible existing path gracefully - * Setting Mocks for chown() to simulate ownership setup - * Setting Mocks for access() to simulate storage path becoming accessible - * Calling GetStorage() and verifying correct retrieval of path, size, and usage - * Calling DeleteStorage() and verifying successful deletion - * Verifying GetStorage() fails after deletion (storage no longer exists) - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, CreateStorageUsingComRpcSuccessExistingIfStorageNotAccessiable) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - std::string actualPath = ""; - uint32_t actualSize = 0; - uint32_t actualUsed = 0; - std::string expectedPath = ""; - - TEST_LOG("### Test CreateStorageUsingComRpcSuccessExistingIfStorageNotAccessiable Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillOnce([](const char* pathname, int mode) { - // Simulate Not accessible - return 1; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - expectedPath = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId; - - EXPECT_CALL(*p_wrapsImplMock, chown(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char *path, uid_t owner, gid_t group) -> int { - // Simulate success - TEST_LOG("### p_wrapsImplMock chown ###"); - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate accessible - return 0; - }); - - /* Verifing GetStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->GetStorage(appId, 1000, 1001, actualPath, actualSize, actualUsed)); - TEST_LOG("GetStorage_Success actualPath = %s actualSize: %u used: %u",actualPath.c_str(), actualSize, actualUsed); - - EXPECT_STREQ(expectedPath.c_str(), actualPath.c_str()); - EXPECT_EQ(size, actualSize); - EXPECT_EQ(0U, actualUsed); - - /* Verify DeleteStorage will success */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - /* Verify GetStorage will fail, it should return Core::ERROR_GENERAL as already deleted the storage */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->GetStorage(appId, 1000, 1001, actualPath, actualSize, actualUsed)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test CreateStorageUsingComRpcSuccessExistingIfStorageNotAccessiable End ###"); -} - -/* Test Case for CreateStorageUsingComRpcSuccessIfPathExists - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() to simulate storage path already exists and is accessible - * Setting Mocks for statvfs() to simulate available disk space - * Calling CreateStorage() with appId and verifying success on first creation - * Re-calling CreateStorage() with the same appId to ensure it returns success if path already exists and is accessible - * Calling DeleteStorage() to verify storage is successfully removed - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, CreateStorageUsingComRpcSuccessIfPathExists) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - TEST_LOG("### Test CreateStorageUsingComRpcSuccessIfPathExists Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Call CreateStorage again with same AppId and expecting to return success */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Delete the Storage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test CreateStorageUsingComRpcSuccessIfPathExists End ###"); -} - -/* Test Case for CreateStorageUsingComRpcFailiureIfEmptyAppId - * Creating Storage Manager Plugin using COM-RPC connection - * Calling CreateStorage() with an empty appId - * Verifying that the method fails and returns Core::ERROR_GENERAL - * Verifying the appropriate error message is set in errorReason ("appId cannot be empty") - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, CreateStorageUsingComRpcFailiureIfEmptyAppId) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = ""; - - TEST_LOG("### Test CreateStorageUsingComRpcFailiureIfEmptyAppId Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Verifing CreateStorage with empty appId and expecting should return Core::ERROR_GENERAL and verify errorReason */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("appId cannot be empty", errorReason.c_str()); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test CreateStorageUsingComRpcFailiureIfEmptyAppId End ###"); -} - -/* Test Case for CreateStorageUsingComRpcFailiureIfSizeExceeded - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() to simulate the storage path is accessible - * Setting Mocks for statvfs() to simulate insufficient available storage space - * Calling CreateStorage() with a size that exceeds available space - * Verifying that the method fails and returns Core::ERROR_GENERAL - * Verifying the appropriate error message is set in errorReason ("Insufficient storage space") - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, CreateStorageUsingComRpcFailiureIfSizeExceeded) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 29046281; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - TEST_LOG("### Test CreateStorageUsingComRpcFailiureIfSizeExceeded Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = 100000; // Total blocks - buf->f_bfree = 0; // Free blocks - buf->f_bavail = 0; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - EXPECT_STREQ("Insufficient storage space", errorReason.c_str()); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test CreateStorageUsingComRpcFailiureIfSizeExceeded End ###"); -} - -/* Test Case for GetStorageUsingComRpcFailiureIfEmptyAppId - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() and statvfs() to simulate accessible storage path and available space - * Calling CreateStorage() with valid appId to set up the environment - * Calling GetStorage() with an empty appId and verifying it returns Core::ERROR_GENERAL - * Verifying that storage retrieval fails due to invalid (empty) appId - * Deleting the previously created storage - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, GetStorageUsingComRpcFailiureIfEmptyAppId) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - std::string actualPath = ""; - uint32_t actualSize = 0; - uint32_t actualUsed = 0; - - TEST_LOG("### Test GetStorageUsingComRpcFailiureIfEmptyAppId Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Verifing GetStorage with empty appId and expecting Core::ERROR_GENERAL */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->GetStorage(" ", 1000, 1001, actualPath, actualSize, actualUsed)); - - /* Delete the Storage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test GetStorageUsingComRpcFailiureIfEmptyAppId End ###"); -} - -/* Test Case for DeleteStorageUsingComRpcFailiureIfEmptyAppId - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() and statvfs() to simulate accessible path and available storage - * Calling CreateStorage() with a valid appId to ensure storage is initialized - * Calling DeleteStorage() with an empty appId and verifying it fails with Core::ERROR_GENERAL - * Verifying that the appropriate error message ("AppId is empty") is set in errorReason - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, DeleteStorageUsingComRpcFailiureIfEmptyAppId) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - TEST_LOG("### Test DeleteStorageUsingComRpcFailiureIfEmptyAppId Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Verifing CreateStorage */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Verifing DeleteStorage with empty appId and expecting Core::ERROR_GENERAL */ - EXPECT_EQ(Core::ERROR_GENERAL, mStorageManagerPlugin->DeleteStorage("", errorReason)); - EXPECT_STREQ("AppId is empty", errorReason.c_str()); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test DeleteStorageUsingComRpcFailiureIfEmptyAppId End ###"); -} - -/* Test Case for ClearStorageUsingJsonRpcSuccess - * Creating Storage Manager Plugin using COM-RPC connection - * Setting Mocks for access() and statvfs() to simulate accessible path and available storage - * Calling CreateStorage() with a valid appId to initialize storage - * Creating a sample file inside the storage path to simulate existing data - * Using JSON-RPC method "clear" to invoke storage content clearing for the specified appId - * Verifying that the previously created file is deleted and storage is cleared successfully - * Calling DeleteStorage() to remove the storage and verify successful deletion - * Releasing the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, ClearStorageUsingJsonRpcSuccess) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - TEST_LOG("### Test ClearStorageUsingJsonRpcSuccess Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Create the Storage for appId */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Mocking for adding some content in storage path of the appId */ - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example1.txt"), appId, std::string("Text file for AiManager testApp")); - - /* Clearing the contents of the appId */ - JsonObject params; - JsonObject resultJson; - params["appId"] = appId; - /* Invoking setAppProperty method */ - status = InvokeServiceMethod(STORAGEMANAGER_CALLSIGN, "clear", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Verify file is not present in the path */ - std::string fileName1 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId + "/example/" + std::string("example1.txt") ; - EXPECT_EQ(false, fileExists(fileName1)); - - /* Verifing DeleteStorage with appId and expecting Core::ERROR_NONE */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test ClearStorageUsingJsonRpcSuccess End ###"); -} - -/* Test Case for ClearStorageUsingJsonRpcFailiureIfEmptyAppId - * Creates Storage Manager Plugin using COM-RPC connection - * Sets mocks for access() and statvfs() to simulate accessible storage path - * Creates storage for a valid appId and adds a sample file inside the storage path - * Attempts to clear storage content using JSON-RPC "clear" method with an empty appId - * Expects failure (Core::ERROR_GENERAL) and verifies that the sample file still exists - * Deletes the storage created for cleanup and verifies success - * Releases the Storage Manager Interface object - */ -TEST_F(StorageManagerTest, ClearStorageUsingJsonRpcFailiureIfEmptyAppId) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId = "testApp"; - - TEST_LOG("### Test ClearStorageUsingJsonRpcFailiureIfEmptyAppId Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Create the Storage for appId */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId, size, path, errorReason)); - - /* Mocking for adding some content in storage path of the appId */ - /* Mocking for adding some content in storage path of the appId */ - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example1.txt"), appId, std::string("Text file for AiManager testApp")); - - /* Clearing the contents of the appId */ - JsonObject params; - JsonObject resultJson; - params["appId"] = ""; - /* Invoking setAppProperty method */ - status = InvokeServiceMethod(STORAGEMANAGER_CALLSIGN, "clear", params, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - - /* Verify file is present in the path */ - std::string fileName1 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId + "/example/" + std::string("example1.txt") ; - EXPECT_EQ(true, fileExists(fileName1)); - - /* Verifing DeleteStorage with appId and expecting Core::ERROR_NONE */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId, errorReason)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test ClearStorageUsingJsonRpcFailiureIfEmptyAppId End ###"); -} - -/* - * Test Case: ClearAllStorageUsingJsonRpcWithoutExemptionSuccess - * Initializes StorageManagerPlugin via COM-RPC connection. - * Mocks access() and statvfs() calls to simulate accessible storage with sufficient space. - * Creates storage for three distinct app IDs (appId1, appId2, appId3). - * Adds sample files inside each app's storage directory. - * Invokes the JSON-RPC "clearAll" method without exempting any app IDs. - * Expects the clearing operation to succeed (Core::ERROR_NONE). - * Verifies that all sample files are deleted from all app storage paths. - * Deletes all created storages and verifies successful deletion. - * Releases the StorageManager interface after test completion. - */ -TEST_F(StorageManagerTest, ClearAllStorageUsingJsonRpcWithoutExemptionSuccess) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId1 = "testApp1"; - std::string appId2 = "testApp2"; - std::string appId3 = "testApp3"; - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcWithoutExemptionSuccess Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - // Simulate success - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Create the Storage for appId1 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId1, size, path, errorReason)); - - /* Create the Storage for appId2 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId2, size, path, errorReason)); - - /* Create the Storage for appId3 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId3, size, path, errorReason)); - - /* Mocking for adding some content in storage path of the appId */ - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example1.txt"), appId1, std::string("Text file for AiManager testApp1")); - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example2.txt"), appId2, std::string("Text file for AiManager testApp2")); - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example3.txt"), appId3, std::string("Text file for AiManager testApp3")); - - /* Clearing the contents of the appId */ - JsonObject params; - JsonObject resultJson; - params["exemptionAppIds"] = {""}; - /* Invoking setAppProperty method */ - status = InvokeServiceMethod(STORAGEMANAGER_CALLSIGN, "clearAll", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Verify file is not present in the path */ - - std::string fileName1 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId1 + "/example/" + std::string("example1.txt") ; - std::string fileName2 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId2 + "/example/" + std::string("example2.txt") ; - std::string fileName3 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId3 + "/example/" + std::string("example3.txt") ; - EXPECT_EQ(false, fileExists(fileName1)); - EXPECT_EQ(false, fileExists(fileName2)); - EXPECT_EQ(false, fileExists(fileName3)); - - /* Verifing DeleteStorage with appId and expecting Core::ERROR_NONE */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId1, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId2, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId3, errorReason)); - - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcWithoutExemptionSuccess End ###"); -} - -/* - * Test Case: ClearAllStorageUsingJsonRpcWithExemptionSuccess - * Initializes StorageManagerPlugin via COM-RPC connection. - * Mocks access() and statvfs() calls to simulate accessible storage with sufficient space. - * Creates storage for three app IDs: appId1, appId2, and appId3. - * Adds example files to each app's storage directory. - * Invokes the JSON-RPC "clearAll" method with exemption list containing appId1 and appId2. - * Expects the clearAll operation to succeed (Core::ERROR_NONE). - * Verifies that files for exempted apps (appId1 and appId2) still exist. - * Verifies that the file for the non-exempted app (appId3) is deleted. - * Deletes all three storages and verifies successful deletion. - * Releases the StorageManager interface after test completion. - */ -TEST_F(StorageManagerTest, ClearAllStorageUsingJsonRpcWithExemptionSuccess) -{ - uint32_t status = Core::ERROR_GENERAL; - - uint32_t size = 1024; - std::string path = " "; - std::string errorReason = ""; - std::string appId1 = "testApp1"; - std::string appId2 = "testApp2"; - std::string appId3 = "testApp3"; - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcWithExemptionSuccess Begin ###"); - - status = CreateStorageManagerInterfaceObjectUsingComRPCConnection(); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_CALL(*p_wrapsImplMock, access(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int mode) { - // Simulate able to access - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* buf) { - TEST_LOG("### p_wrapsImplMock statvfs ###"); - buf->f_bsize = STORAGE_BLOCK_SIZE; // Block size - buf->f_frsize = STORAGE_FR_SIZE; // Fragment size - buf->f_blocks = STORAGE_TOTAL_BLOCKS; // Total blocks - buf->f_bfree = STORAGE_FREE_BLOCKS; // Free blocks - buf->f_bavail = STORAGE_AVAILABLE_BLOCKS; // Available blocks - return 0; - }); - - /* Create the Storage for appId1 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId1, size, path, errorReason)); - - /* Create the Storage for appId2 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId2, size, path, errorReason)); - - /* Create the Storage for appId3 */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->CreateStorage(appId3, size, path, errorReason)); - - /* Mocking for adding some content in storage path of the appId */ - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example1.txt"), appId1, std::string("Text file for AiManager testApp1")); - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example2.txt"), appId2, std::string("Text file for AiManager testApp2")); - createFileAndAddContent(std::string(DEFAULT_APP_STORAGE_PATH), std::string("example3.txt"), appId3, std::string("Text file for AiManager testApp3")); - - /* Clearing the contents of the appId */ - JsonObject params; - JsonObject resultJson; - string applist; - - params["exemptionAppIds"] = {"[\"testApp1\",\"testApp2\"]"}; - - /* Invoking setAppProperty method */ - status = InvokeServiceMethod(STORAGEMANAGER_CALLSIGN, "clearAll", params, resultJson); - EXPECT_EQ(status,Core::ERROR_NONE); - - /* Verify file is present in the path */ - std::string fileName1 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId1 + "/example/" + std::string("example1.txt") ; - std::string fileName2 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId2 + "/example/" + std::string("example2.txt") ; - std::string fileName3 = std::string(DEFAULT_APP_STORAGE_PATH) + std::string("/") + appId3 + "/example/" + std::string("example3.txt") ; - EXPECT_EQ(true, fileExists(fileName1)); - EXPECT_EQ(true, fileExists(fileName2)); - - /* Verify file is not present in the path */ - EXPECT_EQ(false, fileExists(fileName3)); - - /* Verifing DeleteStorage with appId and expecting Core::ERROR_NONE */ - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId1, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId2, errorReason)); - EXPECT_EQ(Core::ERROR_NONE, mStorageManagerPlugin->DeleteStorage(appId3, errorReason)); - if (Core::ERROR_NONE == status) - { - ReleaseStorageManagerInterfaceObjectUsingComRPCConnection(); - } - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcWithExemptionSuccess End ###"); -} - -/* - * Test Case: ClearAllStorageUsingJsonRpcFailiureIfStorageDirectoryNotPresent - * Attempts to remove the storage manager directory (/tmp/persistent/storageManager). - * Verifies that the directory removal was attempted (logs success or failure). - * Invokes the JSON-RPC "clearAll" method with an empty exemption list. - * Expects the clearAll operation to fail with Core::ERROR_GENERAL since the storage directory is missing. - * Does not create or initialize any storage objects prior to the clearAll call. - */ -TEST_F(StorageManagerTest, ClearAllStorageUsingJsonRpcFailiureIfStorageDirectoryNotPresent) -{ - uint32_t status = Core::ERROR_GENERAL; - std::string path = " "; - std::string errorReason = ""; - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcFailiureIfStorageDirectoryNotPresent Begin ###"); - - if (rmdir("/tmp/persistent/storageManager") == 0) - { - TEST_LOG("Directory removed successfully"); - } - else - { - TEST_LOG("Directory removed Failed"); - } - - /* Clearing the contents of the appId */ - JsonObject params; - JsonObject resultJson; - params["exemptionAppIds"] = {"[]"}; - /* Invoking setAppProperty method */ - status = InvokeServiceMethod(STORAGEMANAGER_CALLSIGN, "clearAll", params, resultJson); - EXPECT_EQ(status,Core::ERROR_GENERAL); - - TEST_LOG("### Test ClearAllStorageUsingJsonRpcFailiureIfStorageDirectoryNotPresent End ###"); -} - diff --git a/Tests/L2Tests/tests/Telemetry_L2Test.cpp b/Tests/L2Tests/tests/Telemetry_L2Test.cpp deleted file mode 100755 index 10c51bc..0000000 --- a/Tests/L2Tests/tests/Telemetry_L2Test.cpp +++ /dev/null @@ -1,1244 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include "deepSleepMgr.h" -#include "PowerManagerMock.h" -#include "PowerManagerHalMock.h" -#include "MfrMock.h" - -#include -#include -#include -#include -#include - -#define JSON_TIMEOUT (1000) -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define TELEMETRY_CALLSIGN _T("org.rdk.Telemetry.1") -#define TELEMETRYL2TEST_CALLSIGN _T("L2tests.1") - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::ITelemetry; -using Success = WPEFramework::Exchange::ITelemetry::TelemetrySuccess; -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; - -namespace { -static void removeFile(const char* fileName) -{ - // Use sudo for protected files - if (strcmp(fileName, "/etc/device.properties") == 0 || strcmp(fileName, "/opt/persistent/ds/cecData_2.json") == 0 || strcmp(fileName, "/opt/uimgr_settings.bin") == 0) { - char cmd[256]; - snprintf(cmd, sizeof(cmd), "sudo rm -f %s", fileName); - int ret = system(cmd); - if (ret != 0) { - printf("File %s failed to remove with sudo\n", fileName); - perror("Error deleting file"); - } else { - printf("File %s successfully deleted with sudo\n", fileName); - } - } else { - if (std::remove(fileName) != 0) { - printf("File %s failed to remove\n", fileName); - perror("Error deleting file"); - } else { - printf("File %s successfully deleted\n", fileName); - } - } -} - -static void createFile(const char* fileName, const char* fileContent) -{ - std::ofstream fileContentStream(fileName); - fileContentStream << fileContent; - fileContentStream << "\n"; - fileContentStream.close(); -} -} - -typedef enum : uint32_t { - Telemetry_OnReportUpload = 0x00000001, - Telemetry_StateInvalid = 0x00000000 -}TelemetryL2test_async_events_t; - -class AsyncHandlerMock_Telemetry -{ - public: - AsyncHandlerMock_Telemetry() - { - } - MOCK_METHOD(void, OnReportUpload, (const string& telemetryUploadStatus)); -}; - -/* Notification Handler Class for COM-RPC*/ -class TelemetryNotificationHandler : public Exchange::ITelemetry::INotification { - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::ITelemetry::INotification) - END_INTERFACE_MAP - - public: - TelemetryNotificationHandler(){} - ~TelemetryNotificationHandler(){} - - void OnReportUpload(const string& telemetryUploadStatus) - { - TEST_LOG("onReportUpload event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("onReportUpload received: %s\n", telemetryUploadStatus.c_str()); - /* Notify the requester thread. */ - m_event_signalled |= Telemetry_OnReportUpload; - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms,TelemetryL2test_async_events_t expected_status) - { - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = Telemetry_StateInvalid; - - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; - } - }; - -/* Telemetry L2 test class declaration */ -class Telemetry_L2test : public L2TestMocks { -protected: - - Telemetry_L2test(); - virtual ~Telemetry_L2test() override; - - void TearDown() ; - public: - void OnReportUpload(const string &telemetryUploadStatus); - - /** - * @brief waits for various status change on asynchronous calls - */ - uint32_t WaitForRequestStatus(uint32_t timeout_ms,TelemetryL2test_async_events_t expected_status); - uint32_t CreateTelemetryInterfaceObjectUsingComRPCConnection(); - - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *m_controller_telemetry; - - /** @brief Pointer to the ITelemetry interface */ - Exchange::ITelemetry *m_telemetryplugin; - - Core::Sink notify; - -}; - -/** - * @brief Constructor for Telemetry L2 test class - */ -Telemetry_L2test::Telemetry_L2test() - : L2TestMocks() -{ - Core::hresult status = Core::ERROR_GENERAL; - m_event_signalled = Telemetry_StateInvalid; - createFile("/tmp/pwrmgr_restarted", "2"); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_DS_INIT()) - .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_INIT()) - .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetWakeupSrc(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); - - ON_CALL(*p_rfcApiImplMock, getRFCParameter(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, RFC_ParamData_t* pstParamData) { - if (strcmp("RFC_DATA_ThermalProtection_POLL_INTERVAL", pcParameterName) == 0) { - strcpy(pstParamData->value, "2"); - return WDMP_SUCCESS; - } else if (strcmp("RFC_ENABLE_ThermalProtection", pcParameterName) == 0) { - strcpy(pstParamData->value, "true"); - return WDMP_SUCCESS; - } else if (strcmp("RFC_DATA_ThermalProtection_DEEPSLEEP_GRACE_INTERVAL", pcParameterName) == 0) { - strcpy(pstParamData->value, "6"); - return WDMP_SUCCESS; - } else { - /* The default threshold values will assign, if RFC call failed */ - return WDMP_FAILURE; - } - })); - - EXPECT_CALL(*p_mfrMock, mfrSetTempThresholds(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](int high, int critical) { - EXPECT_EQ(high, 100); - EXPECT_EQ(critical, 110); - return mfrERR_NONE; - })); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_GetPowerState(::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t* powerState) { - *powerState = PWRMGR_POWERSTATE_OFF; // by default over boot up, return PowerState OFF - return PWRMGR_SUCCESS; - })); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetPowerState(::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t powerState) { - // All tests are run without settings file - // so default expected power state is ON - return PWRMGR_SUCCESS; - })); - - EXPECT_CALL(*p_mfrMock, mfrGetTemperature(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](mfrTemperatureState_t* curState, int* curTemperature, int* wifiTemperature) { - *curTemperature = 90; // safe temperature - *curState = (mfrTemperatureState_t)0; - *wifiTemperature = 25; - return mfrERR_NONE; - })); - - EXPECT_CALL(*p_rBusApiImplMock, rbus_set(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](rbusHandle_t handle, const char* name, rbusValue_t value, rbusSetOptions_t* options) { - return RBUS_ERROR_SUCCESS; - })); - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = ActivateService("org.rdk.UserSettings"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = ActivateService("org.rdk.PowerManager"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = ActivateService("org.rdk.Telemetry"); - EXPECT_EQ(Core::ERROR_NONE, status); - - if (CreateTelemetryInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Telemetry_Client"); - } - else - { - EXPECT_TRUE(m_controller_telemetry != nullptr); - if (m_controller_telemetry) - { - EXPECT_TRUE(m_telemetryplugin != nullptr); - if (m_telemetryplugin) { - m_telemetryplugin->Register(¬ify); - } else { - TEST_LOG("m_telemetryplugin is NULL"); - } - } else { - TEST_LOG("m_controller_telemetry is NULL"); - } - } -} - -/** - * @brief Destructor for Telemetry L2 test class - */ -Telemetry_L2test::~Telemetry_L2test() -{ - Core::hresult status = Core::ERROR_GENERAL; - m_event_signalled = Telemetry_StateInvalid; - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_TERM()) - .WillOnce(::testing::Return(PWRMGR_SUCCESS)); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_DS_TERM()) - .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); - - /* DeActivate plugin in constructor */ - status = DeactivateService("org.rdk.PersistentStore"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.UserSettings"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.PowerManager"); - - if (m_telemetryplugin) { - m_telemetryplugin->Unregister(¬ify); - m_telemetryplugin->Release(); - } - - status = DeactivateService("org.rdk.Telemetry"); - EXPECT_EQ(Core::ERROR_NONE, status); - - removeFile("/tmp/pwrmgr_restarted"); - removeFile("/opt/uimgr_settings.bin"); -} - - -void Telemetry_L2test::TearDown() -{ - Core::hresult status = DeactivateService("org.rdk.System"); - TEST_LOG("after deactivate system service and before equality check"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/** - * - * @param[in] message from Telemetry on the change - */ -void Telemetry_L2test::OnReportUpload(const string &telemetryUploadStatus) -{ - TEST_LOG("onReportUpload event triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str= telemetryUploadStatus; - - TEST_LOG("onReportUpload received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= Telemetry_OnReportUpload; - m_condition_variable.notify_one(); -} - -/** - * @brief waits for various status change on asynchronous calls - * - * @param[in] timeout_ms timeout for waiting - */ -uint32_t Telemetry_L2test::WaitForRequestStatus(uint32_t timeout_ms,TelemetryL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = Telemetry_StateInvalid; - - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - - return signalled; -} - - -/** - * @brief Compare two request status objects - * - * @param[in] data Expected value - * @return true if the argument and data match, false otherwise - */ -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s",expected.c_str(),actual.c_str()); - EXPECT_STREQ(expected.c_str(),actual.c_str()); - - return match; -} - -//COM-RPC Changes -uint32_t Telemetry_L2test::CreateTelemetryInterfaceObjectUsingComRPCConnection() -{ - Core::hresult return_value = Core::ERROR_GENERAL; - Core::ProxyType> Engine_Telemetry; - Core::ProxyType Client_Telemetry; - - TEST_LOG("Creating Engine_Telemetry"); - Engine_Telemetry = Core::ProxyType>::Create(); - Client_Telemetry = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(Engine_Telemetry)); - - if (!Client_Telemetry.IsValid()) - { - TEST_LOG("Invalid Client_Telemetry"); - } - else - { - m_controller_telemetry = Client_Telemetry->Open(_T("org.rdk.Telemetry"), ~0, 3000); - if (m_controller_telemetry) - { - m_telemetryplugin = m_controller_telemetry->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -/************Test case Details ************************** -** 1.LogApplicationEvent with eventName and eventValue for success case. -*******************************************************/ - -TEST_F(Telemetry_L2test, LogApplicationEventUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - - string eventName=".....",eventValue="....."; - status = m_telemetryplugin->LogApplicationEvent(eventName,eventValue); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.LogApplicationEvent with empty eventName and eventValue for failure case. -*******************************************************/ - -TEST_F(Telemetry_L2test, LogApplicationEventFailureUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - - string eventName="",eventValue=""; - status = m_telemetryplugin->LogApplicationEvent(eventName,eventValue); - EXPECT_EQ(status,Core::ERROR_GENERAL); - if (status != Core::ERROR_GENERAL) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.LogApplicationEvent with eventName and eventValue for success using Jsonrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetrylogApplicationEventUsingJsonrpc) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - JsonObject expected_status; - - /*With both Params expecting Success*/ - params["eventName"] = "....."; - params["eventValue"] = "....."; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "logApplicationEvent", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); -} - -/************Test case Details ************************** -** 1.LogApplicationEvent with empty eventName and eventValue for failure case using Jsonrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetrylogApplicationFailureEventUsingJsonrpc) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - JsonObject expected_status; - - /*With one Param expecting Fail case */ - params["eventName"] = ""; - params["eventValue"] = ""; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "logApplicationEvent", params, result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_STREQ("null", result["value"].String().c_str()); -} - -/************Test case Details ************************** -** 1.UploadReport with Upload status as SUCCESS. -*******************************************************/ - -TEST_F(Telemetry_L2test, UploadReportUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - uint32_t signalled = Telemetry_StateInvalid; - struct _rbusObject rbObject; - struct _rbusValue rbValue; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusValue_GetString(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return( "SUCCESS")); - - ON_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return &rbValue; - })); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - - status = m_telemetryplugin->UploadReport(); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - signalled = notify.WaitForRequestStatus(JSON_TIMEOUT,Telemetry_OnReportUpload); - EXPECT_TRUE(signalled & Telemetry_OnReportUpload); -} - -/************Test case Details ************************** -** 1.UploadReport with RBUS Error for failure case. -*******************************************************/ - -TEST_F(Telemetry_L2test, UploadReportFailureCaseUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - uint32_t signalled = Telemetry_StateInvalid; - struct _rbusObject rbObject; - struct _rbusValue rbValue; - - //On failure case for covering else case in code// - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_BUS_ERROR, &rbObject); - return RBUS_ERROR_BUS_ERROR; - })); - - status = m_telemetryplugin->UploadReport(); - EXPECT_EQ(status,Core::ERROR_RPC_CALL_FAILED); - if (status != Core::ERROR_RPC_CALL_FAILED) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.AbortReport with RBus Success case using Jsonrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetryAbortReportUsingJsonrpc) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - std::string message; - JsonObject expected_status; - struct _rbusObject rbObject; - - status = InvokeServiceMethod("org.rdk.Telemetry.1", "abortReport", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - - status = InvokeServiceMethod("org.rdk.Telemetry.1", "abortReport", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - -} - -/************Test case Details ************************** -** 1.AbortReport with RBus Error case using Jsonrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetryAbortReportFailureCaseUsingJsonrpc) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - - /**Called rbusMethod_InvokeAsync Twice, where once it returns "RBUS_ERROR_SUCCESS" for IARM ModeChanged - & again returns "RBUS_ERROR_BUS_ERROR" for "ERROR_RPC_CALL_FAILED" Errorcheck**/ - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillOnce(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - return RBUS_ERROR_BUS_ERROR; - })); - - - /* "ERROR_RPC_CALL_FAILED" -- ErrorCheck */ - status = InvokeServiceMethod("org.rdk.Telemetry.1", "abortReport", params, result); - EXPECT_EQ(Core::ERROR_RPC_CALL_FAILED, status); -} - -/************Test case Details ************************** -** 1.AbortReport with RBus Success case using Comrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, AbortReportUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - struct _rbusObject rbObject; - uint32_t signalled = Telemetry_StateInvalid; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - status = m_telemetryplugin->AbortReport(); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.AbortReport with RBus Error case using Comrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, AbortReportFailurecaseUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - struct _rbusObject rbObject; - uint32_t signalled = Telemetry_StateInvalid; - - //On failure case for covering else case in code// - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_BUS_ERROR, &rbObject); - return RBUS_ERROR_BUS_ERROR; - })); - - status = m_telemetryplugin->AbortReport(); - EXPECT_EQ(status,Core::ERROR_RPC_CALL_FAILED); - if (status != Core::ERROR_RPC_CALL_FAILED) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - -} - -/************Test case Details ************************** -** 1.Mocking default.json file creation. -*******************************************************/ - -TEST_F(Telemetry_L2test, ValidateDefaultProfilesFileUsingComrpc) -{ - struct stat buffer; - if (stat("/etc/t2profiles/default.json", &buffer) != 0) { - // File doesn't exist, create it - if (mkdir("/opt/.t2reportprofiles", 0755) == -1 && errno != EEXIST) { - TEST_LOG("Failed to create directory /opt/.t2reportprofiles: %s", strerror(errno)); - return; - } - if (mkdir("/etc/t2profiles", 0755) == -1 && errno != EEXIST) { - TEST_LOG("Failed to create directory /etc/t2profiles: %s", strerror(errno)); - return; - } - std::ofstream jsonFile("/etc/t2profiles/default.json"); - ASSERT_TRUE(jsonFile.is_open()); - jsonFile << "{\n"; - jsonFile << " \"profile\": \"default\",\n"; - jsonFile << " \"version\": \"1.0\",\n"; - jsonFile << " \"markers\": [\n"; - jsonFile << " {\n"; - jsonFile << " \"name\": \"TEST_MARKER\",\n"; - jsonFile << " \"interval\": 3600,\n"; - jsonFile << " \"threshold\": 100\n"; - jsonFile << " }\n"; - jsonFile << " ]\n"; - jsonFile << "}\n"; - jsonFile.close(); - std::ifstream verifyFile("/etc/t2profiles/default.json"); - EXPECT_TRUE(verifyFile.good()); - verifyFile.close(); - } -} - -/************Test case Details ************************** -** 1.Validate uploadReport with no 'UPLOAD_STATUS' using Jsonrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetryReportUploadErrorCheckUsingJsonrpc) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - std::string message; - JsonObject expected_status; - struct _rbusObject rbObject; - - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusValue_GetString(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return("SUCCESS")); - - /**Called rbusObject_GetValue where it returns nullptr to verify "No 'UPLOAD_STATUS' value" for onReportUploadStatus **/ - EXPECT_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return nullptr; - })); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - - status = InvokeServiceMethod("org.rdk.Telemetry.1", "uploadReport", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/************Test case Details ************************** -** 1.Validate uploadReport with no 'UPLOAD_STATUS' using Comrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, OnReportUploadStatusWithNoUploadStatusUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - uint32_t signalled = Telemetry_StateInvalid; - struct _rbusObject rbObject; - - //onReportUploadStatus for "No 'UPLOAD_STATUS' value" - ON_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return(RBUS_ERROR_SUCCESS)); - - ON_CALL(*p_rBusApiImplMock, rbusValue_GetString(::testing::_, ::testing::_)) - .WillByDefault( - ::testing::Return( "SUCCESS")); - - /**Called rbusObject_GetValue where it returns nullptr to verify "No 'UPLOAD_STATUS' value" for onReportUploadStatus **/ - EXPECT_CALL(*p_rBusApiImplMock, rbusObject_GetValue(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](rbusObject_t object, char const* name) { - EXPECT_EQ(object, &rbObject); - EXPECT_EQ(string(name), _T("UPLOAD_STATUS")); - return nullptr; - })); - - ON_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - - status = m_telemetryplugin->UploadReport(); - EXPECT_EQ(status,Core::ERROR_NONE); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - signalled = notify.WaitForRequestStatus(JSON_TIMEOUT,Telemetry_OnReportUpload); - EXPECT_TRUE(signalled & Telemetry_OnReportUpload); - -} - -/************Test case Details ************************** -** 1.setReportProfileStatus Without params and with Params as "No status". -** 2.setReportProfileStatus With Params as "STARTED". -** 3.setReportProfileStatus With Params as "COMPLETE". -** 4.setReportProfileStatus mocking RFC parameter and "NO Status" for failure case. -*******************************************************/ - -TEST_F(Telemetry_L2test, TelemetrysetReportProfileStatusUsingJsonrpc) -{ - - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - std::string message; - JsonObject expected_status; - - /* Without params and with Params as "No status" expecting Fail case*/ - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setReportProfileStatus", params, result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - params["status"] = "No status"; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setReportProfileStatus", params, result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /* With Params as "STARTED" expecting Success*/ - params["status"] = "STARTED"; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setReportProfileStatus", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /* With Params as "COMPLETE" expecting Success*/ - params["status"] = "COMPLETE"; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setReportProfileStatus", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /*mocking RFC parameter and ErrorCheck for "NO Status" */ - EXPECT_CALL(*p_rfcApiImplMock, setRFCParameter(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - return WDMP_FAILURE; - })); - - params["status"] = "STARTED"; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setReportProfileStatus", params, result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_STREQ("null", result["value"].String().c_str()); -} - -/************Test case Details ************************** -** 1.setReportProfileStatus Without params and with Params as "No status" using comrpc. -** 2.setReportProfileStatus With Params as "STARTED" using comrpc. -** 3.setReportProfileStatus With Params as "COMPLETE" using comrpc. -** 4.setReportProfileStatus mocking RFC parameter and "NO Status" for failure case using comrpc. -*******************************************************/ - -TEST_F(Telemetry_L2test, SetReportProfileStatusUsingComrpc) -{ - Core::hresult status = Core::ERROR_GENERAL; - string ReportStatus = ""; - - /* Without ReportStatus and with ReportStatus as "No status" expecting Fail case*/ - status=m_telemetryplugin->SetReportProfileStatus(ReportStatus); - EXPECT_EQ(Core::ERROR_GENERAL, status); - if (status != Core::ERROR_GENERAL) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - ReportStatus = "No status"; - status=m_telemetryplugin->SetReportProfileStatus(ReportStatus); - EXPECT_EQ(Core::ERROR_GENERAL, status); - if (status != Core::ERROR_GENERAL) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /*with ReportStatus as "STARTED" */ - ReportStatus = "STARTED"; - status=m_telemetryplugin->SetReportProfileStatus(ReportStatus); - EXPECT_EQ(Core::ERROR_NONE, status); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /*with ReportStatus as "COMPLETE" */ - ReportStatus = "COMPLETE"; - status=m_telemetryplugin->SetReportProfileStatus(ReportStatus); - EXPECT_EQ(Core::ERROR_NONE, status); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /*mocking RFC parameter and ErrorCheck for "NO Status" */ - EXPECT_CALL(*p_rfcApiImplMock, setRFCParameter(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [](char* pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType) { - return WDMP_FAILURE; - })); - - /*with ReportStatus as "STARTED" */ - ReportStatus = "STARTED"; - status=m_telemetryplugin->SetReportProfileStatus(ReportStatus); - EXPECT_EQ(Core::ERROR_GENERAL, status); - if (status != Core::ERROR_GENERAL) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.SetOptOutTelemetry with OptOut as "false" and "true" using comrpc. -** 2.Verify OptOut value using IsOptOutTelemetry after each SetOptOutTelemetry call using comrpc. -*******************************************************/ -TEST_F(Telemetry_L2test, SetOptOutTelemetry_COMRPC) -{ - Core::hresult status = Core::ERROR_GENERAL; - bool optOut = false; - Success result; - - /* with OptOut as "false" */ - status = m_telemetryplugin->SetOptOutTelemetry(optOut, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result.success); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /* Verify OptOut value using IsOptOutTelemetry */ - optOut = true; //initially setting to true, so that we can verify - bool ret = false; - status = m_telemetryplugin->IsOptOutTelemetry(optOut, ret); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result.success); - EXPECT_FALSE(optOut); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /* with OptOut as "true" */ - optOut = true; - status = m_telemetryplugin->SetOptOutTelemetry(optOut, result); - EXPECT_EQ(Core::ERROR_NONE, status); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /* Verify OptOut value using IsOptOutTelemetry */ - optOut = false; //initially setting to false, so that we can verify - ret = false; - status = m_telemetryplugin->IsOptOutTelemetry(optOut, ret); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(optOut); - EXPECT_TRUE(result.success); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } -} - -/************Test case Details ************************** -** 1.SetOptOutTelemetry with OptOut as "false" and "true" using Jsonrpc. -** 2.Verify OptOut value using IsOptOutTelemetry after each SetOptOutTelemetry call using Jsonrpc. -*******************************************************/ -TEST_F(Telemetry_L2test, SetOptOutTelemetry_JsonRPC) -{ - JSONRPC::LinkType jsonrpc(TELEMETRY_CALLSIGN, TELEMETRYL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - - /* with OptOut as "false" */ - params["Opt-Out"] = false; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setOptOutTelemetry", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /* Verify OptOut value using IsOptOutTelemetry */ - params.Clear(); - status = InvokeServiceMethod("org.rdk.Telemetry.1", "isOptOutTelemetry", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_FALSE(result["Opt-Out"].Boolean()); - EXPECT_TRUE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /* with OptOut as "true" */ - params.Clear(); - params["Opt-Out"] = true; - status = InvokeServiceMethod("org.rdk.Telemetry.1", "setOptOutTelemetry", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_STREQ("null", result["value"].String().c_str()); - - /* Verify OptOut value using IsOptOutTelemetry */ - params.Clear(); - status = InvokeServiceMethod("org.rdk.Telemetry.1", "isOptOutTelemetry", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["Opt-Out"].Boolean()); - EXPECT_TRUE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); -} - -/************Test case Details ************************** - * Transition from POWER_STATE_ON to POWER_STATE_STANDBY_LIGHT_SLEEP - * This will trigger TELEMETRY_EVENT_UPLOADREPORT internally - ********************************************************/ -TEST_F(Telemetry_L2test, TriggerOnPowerModeChangeEvent_LIGHTSLEEP) -{ - Core::ProxyType> mEngine_PowerManager; - Core::ProxyType mClient_PowerManager; - PluginHost::IShell* mController_PowerManager; - uint32_t signalled = Telemetry_StateInvalid; - - TEST_LOG("Creating mEngine_PowerManager"); - mEngine_PowerManager = Core::ProxyType>::Create(); - mClient_PowerManager = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(mEngine_PowerManager)); - - - if (!mClient_PowerManager.IsValid()) { - TEST_LOG("Invalid mClient_PowerManager"); - } else { - mController_PowerManager = mClient_PowerManager->Open(_T("org.rdk.PowerManager"), ~0, 3000); - if (mController_PowerManager) { - auto PowerManagerPlugin = mController_PowerManager->QueryInterface(); - - if (PowerManagerPlugin) { - int keyCode = 0; - - uint32_t clientId = 0; - uint32_t status = PowerManagerPlugin->AddPowerModePreChangeClient("l2-test-client", clientId); - EXPECT_EQ(status, Core::ERROR_NONE); - - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetPowerState(::testing::_)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t powerState) { - EXPECT_EQ(powerState, PWRMGR_POWERSTATE_STANDBY_LIGHT_SLEEP); - return PWRMGR_SUCCESS; - })); - - status = PowerManagerPlugin->SetPowerState(keyCode, PowerState::POWER_STATE_STANDBY_LIGHT_SLEEP, "l2-test"); - EXPECT_EQ(status, Core::ERROR_NONE); - - // some delay to destroy AckController after IModeChanged notification - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); - - signalled = notify.WaitForRequestStatus(JSON_TIMEOUT,Telemetry_OnReportUpload); - EXPECT_TRUE(signalled & Telemetry_OnReportUpload); - - PowerManagerPlugin->Release(); - } else { - TEST_LOG("PowerManagerPlugin is NULL"); - } - mController_PowerManager->Release(); - } else { - TEST_LOG("mController_PowerManager is NULL"); - } - } -} - -/************Test case Details ************************** - * Transition to POWER_STATE_STANDBY_DEEP_SLEEP from POWER_STATE_ON - * This will trigger TELEMETRY_EVENT_ABORTREPORT internally - ********************************************************/ -TEST_F(Telemetry_L2test, TriggerOnPowerModeChangeEvent_DEEPSLEEP) -{ - Core::ProxyType> mEngine_PowerManager; - Core::ProxyType mClient_PowerManager; - PluginHost::IShell* mController_PowerManager; - struct _rbusObject rbObject; - - TEST_LOG("Creating mEngine_PowerManager"); - mEngine_PowerManager = Core::ProxyType>::Create(); - mClient_PowerManager = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(mEngine_PowerManager)); - - if (!mClient_PowerManager.IsValid()) { - TEST_LOG("Invalid mClient_PowerManager"); - } else { - mController_PowerManager = mClient_PowerManager->Open(_T("org.rdk.PowerManager"), ~0, 3000); - if (mController_PowerManager) { - auto PowerManagerPlugin = mController_PowerManager->QueryInterface(); - - if (PowerManagerPlugin) { - int keyCode = 0; - - uint32_t clientId = 0; - uint32_t status = PowerManagerPlugin->AddPowerModePreChangeClient("l2-test-client", clientId); - EXPECT_EQ(status, Core::ERROR_NONE); - - // Expect multiple power state transitions due to deep sleep timeout mechanism - EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetPowerState(::testing::_)) - .Times(::testing::AtLeast(1)) - .WillRepeatedly(::testing::Invoke( - [](PWRMgr_PowerState_t powerState) { - // Accept both DEEP_SLEEP and LIGHT_SLEEP transitions - // Deep sleep timeout causes automatic transition to light sleep - EXPECT_TRUE(powerState == PWRMGR_POWERSTATE_STANDBY_DEEP_SLEEP || - powerState == PWRMGR_POWERSTATE_STANDBY_LIGHT_SLEEP); - return PWRMGR_SUCCESS; - })); - - //Expect calls for rbus_open and rbusMethod_InvokeAsync for AbortReport - EXPECT_CALL(*p_rBusApiImplMock, rbus_open(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Return(RBUS_ERROR_SUCCESS)); - - EXPECT_CALL(*p_rBusApiImplMock, rbusMethod_InvokeAsync(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](rbusHandle_t handle, char const* methodName, rbusObject_t inParams, rbusMethodAsyncRespHandler_t callback, int timeout) { - callback(handle, methodName, RBUS_ERROR_SUCCESS, &rbObject); - return RBUS_ERROR_SUCCESS; - })); - - status = PowerManagerPlugin->SetPowerState(keyCode, PowerState::POWER_STATE_STANDBY_DEEP_SLEEP, "l2-test"); - EXPECT_EQ(status, Core::ERROR_NONE); - - // some delay to destroy AckController after IModeChanged notification - std::this_thread::sleep_for(std::chrono::milliseconds(2500)); - - PowerManagerPlugin->Release(); - } else { - TEST_LOG("PowerManagerPlugin is NULL"); - } - mController_PowerManager->Release(); - } else { - TEST_LOG("mController_PowerManager is NULL"); - } - } -} - -/************Test case Details ************************** -** 1.Trigger OnPrivacyModeChanged notification in Telemetry plugin -** 2.Test UserSettings SetPrivacyMode API triggering Telemetry notification -** 3.Verify that privacy mode changes are propagated to Telemetry plugin -*******************************************************/ -TEST_F(Telemetry_L2test, TriggerOnPrivacyModeChangedNotification_COMRPC) -{ - Core::ProxyType> mEngine_UserSettings; - Core::ProxyType mClient_UserSettings; - PluginHost::IShell* mController_UserSettings; - - TEST_LOG("Creating mEngine_UserSettings"); - mEngine_UserSettings = Core::ProxyType>::Create(); - mClient_UserSettings = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(mEngine_UserSettings)); - - if (!mClient_UserSettings.IsValid()) { - TEST_LOG("Invalid mClient_UserSettings"); - } else { - mController_UserSettings = mClient_UserSettings->Open(_T("org.rdk.UserSettings"), ~0, 3000); - if (mController_UserSettings) { - auto userSettingsPlugin = mController_UserSettings->QueryInterface(); - - if (userSettingsPlugin) { - Core::hresult status = Core::ERROR_GENERAL; - - // Mock RBUS calls for privacy mode notification to T2 - - EXPECT_CALL(*p_rBusApiImplMock, rbus_set(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AtLeast(1)) - .WillRepeatedly(::testing::Invoke( - [](rbusHandle_t handle, const char* name, rbusValue_t value, rbusSetOptions_t* options) { - TEST_LOG("RBUS set called for property: %s", name); - EXPECT_STREQ(name, "Device.X_RDKCENTRAL-COM_Privacy.PrivacyMode"); - return RBUS_ERROR_SUCCESS; - })); - - // Test setting privacy mode from default "SHARE" to "DO_NOT_SHARE" - TEST_LOG("Setting privacy mode to DO_NOT_SHARE"); - status = userSettingsPlugin->SetPrivacyMode("DO_NOT_SHARE"); - EXPECT_EQ(status, Core::ERROR_NONE); - - // Allow time for notification to be processed - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - - // Test setting privacy mode back to "SHARE" - TEST_LOG("Setting privacy mode to SHARE"); - status = userSettingsPlugin->SetPrivacyMode("SHARE"); - EXPECT_EQ(status, Core::ERROR_NONE); - - // Allow time for notification to be processed - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - - // Verify current privacy mode - std::string currentPrivacyMode; - status = userSettingsPlugin->GetPrivacyMode(currentPrivacyMode); - EXPECT_EQ(status, Core::ERROR_NONE); - EXPECT_STREQ(currentPrivacyMode.c_str(), "SHARE"); - - userSettingsPlugin->Release(); - } else { - TEST_LOG("UserSettingsPlugin is NULL"); - } - mController_UserSettings->Release(); - } else { - TEST_LOG("mController_UserSettings is NULL"); - } - } -} diff --git a/Tests/L2Tests/tests/UsbAccess_L2Test.cpp b/Tests/L2Tests/tests/UsbAccess_L2Test.cpp deleted file mode 100755 index 89d52fe..0000000 --- a/Tests/L2Tests/tests/UsbAccess_L2Test.cpp +++ /dev/null @@ -1,649 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include - -#define JSON_TIMEOUT (1000) -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); -#define USBACCESS_CALLSIGN _T("org.rdk.UsbAccess.1") -#define USBACCESSL2TEST_CALLSIGN _T("L2tests.1") - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; - -typedef enum : uint32_t { - UsbAccess_onUSBMountChanged = 0x00000001, - UsbAccess_onArchieveLogs = 0x00000002, - UsbAccess_StateInvalid = 0x00000000 - -}UsbAccessL2test_async_events_t; - -char buffer[1024]; - -/** - * @brief Compare two request status objects - * - * @param[in] data Expected value - * @return true if the argument and data match, false otherwise - */ - -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s",expected.c_str(),actual.c_str()); - EXPECT_STREQ(expected.c_str(),actual.c_str()); - return match; -} - -/** - * @brief Internal test mock class - * - * Note that this is for internal test use only and doesn't mock any actual - * concrete interface. - */ - -class AsyncHandlerMock_USB -{ - public: - AsyncHandlerMock_USB() - { - } - MOCK_METHOD(void, onUSBMountChanged, (const JsonObject &message)); - MOCK_METHOD(void, onArchiveLogs, (const JsonObject &message)); -}; - -/* UsbAccess L2 test class declaration */ - -class UsbAccess_L2test : public L2TestMocks { - protected: - Core::JSONRPC::Message message; - string response; - IARM_EventHandler_t iarmEventHandler = nullptr; - virtual ~UsbAccess_L2test() override; - - public: - UsbAccess_L2test(); - void onUSBMountChanged(const JsonObject &message); - void onArchiveLogs(const JsonObject &message); - std::string verify_getFileListContents(string *str1); - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, UsbAccessL2test_async_events_t expected_status); - - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; -}; - -/** - * @brief Constructor for UsbAccess L2 test class - */ - -UsbAccess_L2test:: UsbAccess_L2test():L2TestMocks() -{ - TEST_LOG("UsbAccess_L2test constructor"); - uint32_t status = Core::ERROR_GENERAL; - Core::JSONRPC::Message message; - - ON_CALL(*p_iarmBusImplMock, IARM_Bus_RegisterEventHandler(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const char* ownerName, IARM_EventId_t eventId, IARM_EventHandler_t handler) { - if ((string(IARM_BUS_SYSMGR_NAME) == string(ownerName)) && (eventId == IARM_BUS_SYSMGR_EVENT_USB_MOUNT_CHANGED)) { - - iarmEventHandler = handler; - } - return IARM_RESULT_SUCCESS; - })); - status = ActivateService("org.rdk.UsbAccess"); - EXPECT_EQ(Core::ERROR_NONE, status); - - std::ofstream file("/etc/device.properties"); - file << "MODEL_NUM=HSTP11MWR"; - file.close(); -} - -/** - * @brief Destructor for UsbAccess L2 test class - */ - -UsbAccess_L2test:: ~UsbAccess_L2test(){ - - TEST_LOG("UsbAccess_L2test Destructor"); - uint32_t status = Core::ERROR_GENERAL; - - status = DeactivateService("org.rdk.UsbAccess"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/** - * @brief waits for various status change on asynchronous calls - * - * @param[in] timeout_ms timeout for waiting - */ - -uint32_t UsbAccess_L2test::WaitForRequestStatus(uint32_t timeout_ms, UsbAccessL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = UsbAccess_StateInvalid; - - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void UsbAccess_L2test::onUSBMountChanged(const JsonObject &message) -{ - TEST_LOG("onUSBMountChanged triggered ***\n"); - std::unique_lock lock(m_mutex); - - std::string str; - message.ToString(str); - - /* Notify the requester thread. */ - m_event_signalled |= UsbAccess_onUSBMountChanged; - m_condition_variable.notify_one(); -} - -void UsbAccess_L2test::onArchiveLogs(const JsonObject &message) -{ - TEST_LOG("onArchiveLogs event triggered ******\n"); - std::unique_lock lock(m_mutex); - - std::string str; - message.ToString(str); - - TEST_LOG("onArchiveLogs received: %s\n", str.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= UsbAccess_onArchieveLogs; - m_condition_variable.notify_one(); -} - -/* Function to verify the contents of getFileList method in the FileList Test case */ -std::string UsbAccess_L2test::verify_getFileListContents(string *str1) -{ - string str2 = *str1; - - /* Verify the contents of getFileList in the below list as set in L2-tests.yml */ - std::list search_list = { - "{\"name\":\".\",\"t\":\"d\"}", - "{\"name\":\"..\",\"t\":\"d\"}", - "{\"name\":\"PreviousLogs\",\"t\":\"d\"}", - "{\"name\":\"test.png\",\"t\":\"f\"}", - "{\"name\":\"test.txt\",\"t\":\"f\"}" - }; - - for (auto const& i : search_list) { - int pos = str2.find(i); - if(pos >= 0) - str2.erase(pos, i.length()); - pos = str2.find(",,"); - if(pos >= 0) - str2.erase(pos, 2); - } - /* str2 will contain only “[]” if the contents of getFileList are there in the above search_list */ - return str2; -} - -/******************************************************** -************Test case Details ************************** -** 1. Triggered getFileList Method -** 2. Verify the response of getFileList Method -** 3. Verify the event onUSBMountChanged getting triggered -*******************************************************/ - -TEST_F(UsbAccess_L2test, FileList) -{ - JSONRPC::LinkType jsonrpc(USBACCESS_CALLSIGN, USBACCESSL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - std::string message; - JsonObject expected_status; - uint32_t signalled = UsbAccess_StateInvalid; - - EXPECT_CALL(*p_udevImplMock, udev_enumerate_get_list_entry(testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x3))); - - EXPECT_CALL(*p_udevImplMock, udev_list_entry_get_name(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_parent_with_subsystem_devtype(testing::_, testing::_, testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x5))); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devtype(testing::_)) - .WillRepeatedly(testing::Return("disk")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devnode(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - /* getFileList returns null as getmntent() system call used by getMounted API which is being invoked internally in the getFileList doesn't return any mounted path*/ - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getFileList", params, result); - EXPECT_FALSE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); - - EXPECT_CALL(*p_wrapsImplMock, getmntent(testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](FILE*) -> struct mntent* { - static struct mntent entry1; - - entry1.mnt_fsname = const_cast("/dev/sda1"); - entry1.mnt_dir = const_cast("/run/media/sda1/logs"); - - static int callCount = 0; - if (callCount == 0) { - callCount++; - return &entry1; - } else { - return static_cast(NULL); - } - })); - - /* - * getFileList returns mounted path for which the contents are returned - * Contents include a list of files and directories on the mounted path - * Files with the extension mentioned in REGEX_FILE are only returned - * REGEX_FILE = "^[^,`~?!$@#%^&*+={}\\[\\]<>]+\\.(png|jpg|jpeg|tiff|tif|bmp|mp4|mov|avi|mp3|wav|m4a|flac|aac|wma|txt|bin|enc|ts)$" - */ - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getFileList", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - - string getFileListContents_path1 = result["contents"].String().c_str(); - string output1 = verify_getFileListContents(&getFileListContents_path1); - EXPECT_STREQ("/run/media/sda1/logs", result["path"].String().c_str()); - EXPECT_STREQ("[]", output1.c_str()); - - std::cout << "output1 = " << output1 << "\n"; - - /* Subscribe to the "onUSBMountChanged" event */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onUSBMountChanged"), - &AsyncHandlerMock_USB::onUSBMountChanged, - &async_handler); - EXPECT_EQ(Core::ERROR_NONE, status); - - - message = "{\"mounted\":true,\"device\":\"\\/dev\\/sda1\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onUSBMountChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &UsbAccess_L2test::onUSBMountChanged)); - - IARM_Bus_SYSMgr_EventData_t usbEventData; - usbEventData.data.usbMountData.mounted= true; - strncpy(usbEventData.data.usbMountData.dir, "/dev/sda1", sizeof(usbEventData.data.usbMountData.dir)); - iarmEventHandler(IARM_BUS_SYSMGR_NAME, IARM_BUS_SYSMGR_EVENT_USB_MOUNT_CHANGED, &usbEventData, 1); - - EXPECT_CALL(*p_udevImplMock, udev_enumerate_get_list_entry(testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x3))); - - EXPECT_CALL(*p_udevImplMock, udev_list_entry_get_name(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda2")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_parent_with_subsystem_devtype(testing::_, testing::_, testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x5))); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devtype(testing::_)) - .WillRepeatedly(testing::Return("disk")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devnode(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda2")); - - EXPECT_CALL(*p_wrapsImplMock, getmntent(testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](FILE*) -> struct mntent* { - static struct mntent entry2; - - entry2.mnt_fsname = const_cast("/dev/sda2"); - entry2.mnt_dir = const_cast("/run/media/sda2/logs"); - - static int callCount = 0; - if (callCount == 0) { - callCount++; - return &entry2; - } else { - return static_cast(NULL); - } - })); - - /* - * getFileList returns a mounted path which is different than the one which is verified above - * Contents include a list of files and directories on the mounted path - * Files with the extension mentioned in REGEX_FILE are only returned - * REGEX_FILE = "^[^,`~?!$@#%^&*+={}\\[\\]<>]+\\.(png|jpg|jpeg|tiff|tif|bmp|mp4|mov|avi|mp3|wav|m4a|flac|aac|wma|txt|bin|enc|ts)$" - */ - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getFileList", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - - string getFileListContents_path2 = result["contents"].String().c_str(); - string output2 = verify_getFileListContents(&getFileListContents_path2); - EXPECT_STREQ("/run/media/sda2/logs", result["path"].String().c_str()); - EXPECT_STREQ("[]", output2.c_str()); - - message = "{\"mounted\":true,\"device\":\"\\/dev\\/sda2\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onUSBMountChanged(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &UsbAccess_L2test::onUSBMountChanged)); - - IARM_Bus_SYSMgr_EventData_t usbEventData1; - usbEventData1.data.usbMountData.mounted= true; - strncpy(usbEventData1.data.usbMountData.dir, "/dev/sda2", sizeof(usbEventData1.data.usbMountData.dir)); - iarmEventHandler(IARM_BUS_SYSMGR_NAME, IARM_BUS_SYSMGR_EVENT_USB_MOUNT_CHANGED, &usbEventData1, 1); - - signalled = WaitForRequestStatus(JSON_TIMEOUT,UsbAccess_onUSBMountChanged); - EXPECT_TRUE(signalled & UsbAccess_onUSBMountChanged); - - /* Unregister for event */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onUSBMountChanged")); -} - -/******************************************************** -************Test case Details ************************** -** 1. Triggered getAvailableFirmwareFiles & updateFirmware Methods -** 2. Verify getAvailableFirmwareFiles & updateFirmware method getting triggered and verify their responses -*******************************************************/ - -TEST_F(UsbAccess_L2test, FirmwareUpdate) -{ - JSONRPC::LinkType jsonrpc(USBACCESS_CALLSIGN, USBACCESSL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - - EXPECT_CALL(*p_udevImplMock, udev_enumerate_get_list_entry(testing::_)) - .WillOnce(testing::Return(reinterpret_cast(0x3))); - - EXPECT_CALL(*p_udevImplMock, udev_list_entry_get_name(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_parent_with_subsystem_devtype(testing::_, testing::_, testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x5))); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devtype(testing::_)) - .WillRepeatedly(testing::Return("disk")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devnode(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_wrapsImplMock, getmntent(testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](FILE*) -> struct mntent* { - static struct mntent entry1; - - entry1.mnt_fsname = const_cast("/dev/sda1"); - entry1.mnt_dir = const_cast("/run/sda1/"); - - static int callCount = 0; - if (callCount == 0) { - callCount++; - return &entry1; - } else { - return static_cast(NULL); - } - })); - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "updateFirmware", params, result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_FALSE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); - - EXPECT_CALL(*p_wrapsImplMock, v_secure_system(::testing::_, ::testing::_)) - .Times(1) - .WillOnce(::testing::Invoke( - [&](const char* command, va_list args) { - /*Since we have added the "etc/device.properties" file in the test fixture, it can be opened, - and the model number is now available. Therefore, we need to change the input parameter for this test API as well as the corresponding string in the system command to match the model number.*/ - va_list args2; - va_copy(args2,args); - char strFmt[256]; - vsnprintf(strFmt, sizeof(strFmt), command, args2); - EXPECT_EQ(string(strFmt), string(_T("/lib/rdk/userInitiatedFWDnld.sh usb '/tmp/reboot/' 'HSTP11MWR.bin' 0 >> /opt/logs/swupdate.log &"))); - return 0; - })); - - /* Gets a list of firmware files on the device. These files should start with the PMI or model number for that device and end with '.bin'. Firmware files are scanned in the root directories */ - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getAvailableFirmwareFiles", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - EXPECT_STREQ("[\"\\/run\\/sda1\\/UsbTestFWUpdate\\/HSTP11MWR_3.11p5s1_VBN_sdy.bin\",\"\\/run\\/sda1\\/UsbProdFWUpdate\\/HSTP11MWR_4.11p5s1_VBN_sdy.bin\",\"\\/run\\/sda1\\/HSTP11MWR_5.11p5s1_VBN_sdy.bin\"]" -, result["availableFirmwareFiles"].String().c_str()); - - /* Updates the firmware using the specified file retrieved from the 'getAvailableFirmwareFiles' method. The firmware file path to use for the update*/ - params["fileName"] = "/tmp/reboot/HSTP11MWR.bin"; - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "updateFirmware", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - -} - -/******************************************************** -************Test case Details ************************** -** 1. Triggered getLinks, clearLink & createLink Methods -** 2. Verify getLinks, clearLink & createLink method getting triggered and verify their responses -*******************************************************/ - -TEST_F(UsbAccess_L2test, SymLinkoperations) -{ - JSONRPC::LinkType jsonrpc(USBACCESS_CALLSIGN, USBACCESSL2TEST_CALLSIGN); - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - std::string message; - JsonObject expected_status; - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "clearLink", params , result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_FALSE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "createLink", params , result); - EXPECT_EQ(Core::ERROR_GENERAL, status); - EXPECT_FALSE(result["success"].Boolean()); - EXPECT_STREQ("null", result["value"].String().c_str()); - - - EXPECT_CALL(*p_udevImplMock, udev_enumerate_get_list_entry(testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x3))); - - EXPECT_CALL(*p_udevImplMock, udev_list_entry_get_name(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_parent_with_subsystem_devtype(testing::_, testing::_, testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x5))); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devtype(testing::_)) - .WillRepeatedly(testing::Return("disk")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devnode(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_wrapsImplMock, getmntent(testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](FILE*) -> struct mntent* { - static struct mntent entry1; - - entry1.mnt_fsname = const_cast("/dev/sda1"); // Set the value for mnt_fsname - entry1.mnt_dir = const_cast("/run/media/sda1/logs"); // Set the value for mnt_dir - - static int callCount = 0; - if (callCount == 0) { - callCount++; - return &entry1; - } else { - return static_cast(NULL); - } - })); - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getLinks", params , result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - - /* Creates a symbolic link to the root folder of the USB drive */ - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "createLink", params , result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - EXPECT_STREQ("http://localhost:50050/usbdrive", result["baseURL"].String().c_str()); - - /* Returns the list of links and associated baseURL paths */ - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getLinks", params , result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - EXPECT_STREQ("[{\"path\":\"\\/run\\/media\\/sda1\\/logs\",\"baseURL\":\"http:\\/\\/localhost:50050\\/usbdrive\"}]", result["links"].String().c_str()); - - /* Clears or removes the symbolic link created by the 'createLink' method */ - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "clearLink", params , result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "getLinks", params , result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); -} - -/******************************************************** -************Test case Details ************************** -** 1. Subscribe for onArchiveLogs Events -** 2. Verify onArchiveLogs event triggered and verify the response -*******************************************************/ - -TEST_F(UsbAccess_L2test,UsbAccessArchiveLogs) -{ - JSONRPC::LinkType jsonrpc(USBACCESS_CALLSIGN,USBACCESSL2TEST_CALLSIGN); - StrictMock async_handler; - uint32_t status = Core::ERROR_GENERAL; - JsonObject params; - JsonObject result; - uint32_t signalled = UsbAccess_StateInvalid; - std::string message; - JsonObject expected_status; - - EXPECT_CALL(*p_udevImplMock, udev_enumerate_get_list_entry(testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x3))); - - EXPECT_CALL(*p_udevImplMock, udev_list_entry_get_name(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_parent_with_subsystem_devtype(testing::_, testing::_, testing::_)) - .WillRepeatedly(testing::Return(reinterpret_cast(0x5))); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devtype(testing::_)) - .WillRepeatedly(testing::Return("disk")); - - EXPECT_CALL(*p_udevImplMock, udev_device_get_devnode(testing::_)) - .WillRepeatedly(testing::Return("/dev/sda1")); - - EXPECT_CALL(*p_wrapsImplMock, getmntent(testing::_)) - .WillRepeatedly(::testing::Invoke( - [&](FILE*) -> struct mntent* { - static struct mntent entry1; - - entry1.mnt_fsname = const_cast("/dev/sda1"); - entry1.mnt_dir = const_cast("/run/media/sda1/Logs"); - - static int callCount = 0; - if (callCount == 0) { - callCount++; - return &entry1; - } else { - return static_cast(NULL); - } - })); - - ON_CALL(*p_wrapsImplMock, v_secure_popen(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](const char *direction, const char *command, va_list args) -> FILE* { - const char* valueToReturn = NULL; - va_list args2; - va_copy(args2, args); - char strFmt[256]; - vsnprintf(strFmt, sizeof(strFmt), command, args2); - va_end(args2); - if (strcmp(strFmt, "/lib/rdk/usbLogUpload.sh /run/media/sda1/Logs") == 0) { - valueToReturn = "/run/media/sda1/Logs/5C3400F15492_Logs_12-05-22-10-41PM.tgz"; - } - if (valueToReturn != NULL) { - memset(buffer, 0, sizeof(buffer)); - strcpy(buffer, valueToReturn); - FILE* pipe = fmemopen(buffer, strlen(buffer), "r"); - return pipe; - } else { - return nullptr; - } - })); - - /* Register for abortlog event. */ - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onArchiveLogs"), - &AsyncHandlerMock_USB::onArchiveLogs, - &async_handler); - - EXPECT_EQ(Core::ERROR_NONE, status); - - /* Request status for onArchive. */ - message = "{\"error\":\"none\",\"success\":true,\"path\":\"\\/run\\/media\\/sda1\\/Logs\\/5C3400F15492_Logs_12-05-22-10-41PM.tgz\"}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, onArchiveLogs(MatchRequestStatus(expected_status))) - .WillOnce(Invoke(this, &UsbAccess_L2test::onArchiveLogs)); - - /* Compresses and uploads device logs into attached USB drive */ - params["path"] = "/run/media/sda1/Logs"; - params["error"] = "none"; - params["success"] = "true"; - status = InvokeServiceMethod("org.rdk.UsbAccess.1", "ArchiveLogs", params, result); - EXPECT_EQ(Core::ERROR_NONE, status); - EXPECT_TRUE(result["success"].Boolean()); - - signalled = WaitForRequestStatus(JSON_TIMEOUT,UsbAccess_onArchieveLogs); - EXPECT_TRUE(signalled & UsbAccess_onArchieveLogs); - - /* Unregister for events. */ - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onArchiveLogs")); -} - diff --git a/Tests/L2Tests/tests/UsbDevice_L2Test.cpp b/Tests/L2Tests/tests/UsbDevice_L2Test.cpp deleted file mode 100755 index f3ef6c4..0000000 --- a/Tests/L2Tests/tests/UsbDevice_L2Test.cpp +++ /dev/null @@ -1,2476 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -#define JSON_TIMEOUT (1000) -#define USBDEVICE_CALLSIGN _T("org.rdk.UsbDevice") -#define USBDEVICEL2TEST_CALLSIGN _T("L2tests.1") - -#define MOCK_USB_DEVICE_BUS_NUMBER_1 100 -#define MOCK_USB_DEVICE_ADDRESS_1 001 -#define MOCK_USB_DEVICE_PORT_1 123 - -#define MOCK_USB_DEVICE_BUS_NUMBER_2 101 -#define MOCK_USB_DEVICE_ADDRESS_2 002 -#define MOCK_USB_DEVICE_PORT_2 124 - -#define LIBUSB_CONFIG_ATT_SELF_POWERED 0x40 -#define LIBUSB_CONFIG_ATT_BUS_POWERED 0x80 -#define MOCK_USB_DEVICE_SERIAL_NO "0401805e4532973503374df52a239c898397d348" -#define MOCK_USB_DEVICE_MANUFACTURER "USB" -#define MOCK_USB_DEVICE_PRODUCT "SanDisk 3.2Gen1" -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::IUSBDevice; - -typedef enum : uint32_t { - USBDevice_onDevicePluggedIn = 0x00000001, - USBDevice_onDevicePluggedOut = 0x00000002, - USBDevice_StateInvalid = 0x00000000 -}USBDeviceL2test_async_events_t; - -class AsyncHandlerMock_USBDevice -{ - public: - AsyncHandlerMock_USBDevice() - { - } - MOCK_METHOD(void, OnDevicePluggedIn, (const Core::JSON::Container& eventPayload)); - MOCK_METHOD(void, OnDevicePluggedOut,(const Core::JSON::Container& eventPayload)); -}; - -class USBDeviceNotificationHandler : public Exchange::IUSBDevice::INotification { - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - WPEFramework::Exchange::IUSBDevice::USBDevice m_usb_device; - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IUSBDevice::INotification) - END_INTERFACE_MAP - - public: - USBDeviceNotificationHandler(){} - ~USBDeviceNotificationHandler(){} - - void OnDevicePluggedIn(const Exchange::IUSBDevice::USBDevice &device) - { - TEST_LOG("OnDevicePluggedIn event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnDevicePluggedIn received device.deviceClass: %d device.deviceSubclass: %d device.deviceName: %s device.devicePath: %s", - device.deviceClass, - device.deviceSubclass, - device.deviceName.c_str(), - device.devicePath.c_str()); - - /* Notify the requester thread. */ - m_event_signalled |= USBDevice_onDevicePluggedIn; - - m_usb_device.deviceClass = device.deviceClass; - m_usb_device.deviceSubclass = device.deviceSubclass; - m_usb_device.deviceName = device.deviceName; - m_usb_device.devicePath = device.devicePath; - - m_condition_variable.notify_one(); - } - - void OnDevicePluggedOut(const Exchange::IUSBDevice::USBDevice &device) - { - TEST_LOG("OnDevicePluggedOut event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("OnDevicePluggedOut received"); - - /* Notify the requester thread. */ - m_event_signalled |= USBDevice_onDevicePluggedOut; - - m_usb_device.deviceClass = device.deviceClass; - m_usb_device.deviceSubclass = device.deviceSubclass; - m_usb_device.deviceName = device.deviceName; - m_usb_device.devicePath = device.devicePath; - - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, USBDeviceL2test_async_events_t expected_status, Exchange::IUSBDevice::USBDevice &actual_usbDevice) - { - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = USBDevice_StateInvalid; - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - actual_usbDevice.deviceClass = m_usb_device.deviceClass; - actual_usbDevice.deviceSubclass = m_usb_device.deviceSubclass; - actual_usbDevice.deviceName = m_usb_device.deviceName; - actual_usbDevice.devicePath = m_usb_device.devicePath; - - m_event_signalled = USBDevice_StateInvalid; - return signalled; - } - }; - -class USBDeviceTest : public L2TestMocks { -protected: - virtual ~USBDeviceTest() override; - -protected: - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceAttached = nullptr; - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceDetached = nullptr; - - public: - USBDeviceTest(); - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, USBDeviceL2test_async_events_t expected_status); - uint32_t CreateUSBDeviceInterfaceObjectUsingComRPCConnection(); - void Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address, uint8_t device_class); - void Mock_SetSerialNumberInUSBDevicePath(); - - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *m_controller_usbdevice; - - /** @brief Pointer to the IUSBDevice interface */ - Exchange::IUSBDevice *m_usbdeviceplugin; -}; - -USBDeviceTest:: USBDeviceTest():L2TestMocks() -{ - Core::JSONRPC::Message message; - string response; - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Test Constructor"); - - /* Set all the asynchronouse event handler with libusb to handle various events*/ - ON_CALL(*p_libUSBApiImplMock, libusb_hotplug_register_callback(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](libusb_context *ctx, int events, int flags, int vendor_id, int product_id, int dev_class, - libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *callback_handle) { - if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == events) { - libUSBHotPlugCbDeviceAttached = cb_fn; - *callback_handle = 1; - } - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == events) { - libUSBHotPlugCbDeviceDetached = cb_fn; - *callback_handle = 2; - } - return LIBUSB_SUCCESS; - })); - - TEST_LOG("Activate USBDevice plugin"); - - /* Activate plugin in constructor */ - status = ActivateService(USBDEVICE_CALLSIGN); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -/** - * @brief Destructor for SystemServices L2 test class - */ -USBDeviceTest::~USBDeviceTest() -{ - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Test Destructor"); - - ON_CALL(*p_libUSBApiImplMock, libusb_hotplug_deregister_callback(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](libusb_context *ctx, libusb_hotplug_callback_handle callback_handle) { - if (callback_handle == 1) { - libUSBHotPlugCbDeviceAttached = nullptr; - } else if (callback_handle == 2) { - libUSBHotPlugCbDeviceDetached = nullptr; - } - })); - TEST_LOG("DeActivate USBDevice plugin"); - status = DeactivateService(USBDEVICE_CALLSIGN); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -uint32_t USBDeviceTest::WaitForRequestStatus(uint32_t timeout_ms, USBDeviceL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = USBDevice_StateInvalid; - - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void USBDeviceTest::Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address, uint8_t device_class) -{ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillByDefault( - [bus_number, device_address, device_class](libusb_device *dev, struct libusb_device_descriptor *desc) { - if ((bus_number == dev->bus_number) && - (device_address == dev->device_address)) - { - desc->bDeviceSubClass = device_class; - desc->bDeviceClass = device_class; - } - return LIBUSB_SUCCESS; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillByDefault(::testing::Return(device_address)); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillByDefault(::testing::Return(bus_number)); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - if (device_address == MOCK_USB_DEVICE_ADDRESS_1) - { - std::string vendorFileName = "/tmp/block/sda/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "Generic" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sda/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Flash Disk" << std::endl; - outModelStream.close(); - } - - if (device_address == MOCK_USB_DEVICE_ADDRESS_2) - { - std::string vendorFileName = "/tmp/block/sdb/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "JetFlash" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sdb/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Transcend_16GB" << std::endl; - outModelStream.close(); - } -} - -void USBDeviceTest::Mock_SetSerialNumberInUSBDevicePath() -{ - std::string serialNumFileName1 = "/tmp/bus/usb/devices/100-123/serial"; - std::ofstream serialNumOutFile1(serialNumFileName1); - - if (!serialNumOutFile1) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile1 << "B32FD507" << std::endl; - serialNumOutFile1.close(); - - std::string serialNumFileName2 = "/tmp/bus/usb/devices/101-124/serial"; - std::ofstream serialNumOutFile2(serialNumFileName2); - - if (!serialNumOutFile2) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile2<< "UEUIRCXT" << std::endl; - serialNumOutFile2.close(); -} - -uint32_t USBDeviceTest::CreateUSBDeviceInterfaceObjectUsingComRPCConnection() -{ - uint32_t return_value = Core::ERROR_GENERAL; - Core::ProxyType> Engine_USBDevice; - Core::ProxyType Client_USBDevice; - - TEST_LOG("Creating Engine_USBDevice"); - Engine_USBDevice = Core::ProxyType>::Create(); - Client_USBDevice = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(Engine_USBDevice)); - - TEST_LOG("Creating Engine_USBDevice Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - Engine_USBDevice->Announcements(mClient_USBDevice->Announcement()); -#endif - if (!Client_USBDevice.IsValid()) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - m_controller_usbdevice = Client_USBDevice->Open(USBDEVICE_CALLSIGN, ~0, 3000); - if (m_controller_usbdevice) - { - m_usbdeviceplugin = m_controller_usbdevice->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -/** - * @brief Compare two request status objects - * - * @param[in] data Expected value - * @return true if the argument and data match, false otherwise - */ -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s",expected.c_str(),actual.c_str()); - EXPECT_STREQ(expected.c_str(),actual.c_str()); - - return match; -} - -/* Test Case for verifying USB Device Plugged In and Plugged Out Notification. - * Activating USB Device Plugin, - * Setting Mocks for simulating the plugged in and plugged out events - * Sending Plugged In event and Verify USBDevice struct with Valid device details - * Deactivating the USB Device -*/ -TEST_F(USBDeviceTest, devicePluggedInAndPluggedOut) -{ - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - - TEST_LOG("** Test Case: devicePluggedInAndPluggedOut Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - TEST_LOG("** Test Case: devicePluggedInAndPluggedOut Ended **"); -} - -/* Test Case for getDeviceList Method with single mass storage USB - * Activating USB Device Plugin, - * Setting Mocks for simulating the plugged in event - * Setting Mocks to send the usb details like serial number, device address, port and bus numbers - * Sending Plugged In event and Verify USBDevice struct with Valid device details - * Calling the getDeviceList function and verify the Iterator and Release it - * Deactivating the USB Device -*/ -TEST_F(USBDeviceTest, getDeviceListUsingWithSingleMassStorageUSBComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::IUSBDeviceIterator* devices = nullptr; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - - TEST_LOG("** Test Case: getDeviceListUsingWithSingleMassStorageUSBComRpcConnectionSuccessCase Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* Mock for Device List, 1 Device */ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - /* Call GetDeviceList method */ - TEST_LOG("Getting DeviceList Values"); - status = m_usbdeviceplugin->GetDeviceList(devices); - EXPECT_EQ(status,Core::ERROR_NONE); - - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - ASSERT_TRUE(devices != nullptr); - ASSERT_TRUE(1 == devices->Count()); /* Verify device count */ - ASSERT_TRUE(devices->Next(actual_usbDevice_dev_list)); - /* Verify device details */ - ASSERT_EQ(actual_usbDevice_dev_list.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice_dev_list.devicePath, std::string("/dev/sda")); - - devices->Release(); - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - - TEST_LOG("** Test Case: getDeviceListUsingWithSingleMassStorageUSBComRpcConnectionSuccessCase Ended **"); -} - -/* Test Case for getDeviceList Method with multiple mass storage USB - * Activating USB Device Plugin, - * Setting Mocks for simulating the plugged in event - * Setting Mocks to send the usb details like serial number, device address, port and bus numbers - * Sending Plugged In event and Verify USBDevice struct with Valid device details - * Calling the getDeviceList function and verify the Iterator and Release it - * Deactivating the USB Device -*/ -TEST_F(USBDeviceTest, getDeviceListUsingWithMultipleMassStorageUSBComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::IUSBDeviceIterator* devices = nullptr; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - - TEST_LOG("** Test Case: getDeviceListUsingWithMultipleMassStorageUSBComRpcConnectionSuccessCase Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - - if (m_usbdeviceplugin) - { - std::string message; - - m_usbdeviceplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* HotPlug Attach Device 2 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_2; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_2; - dev.port_number = MOCK_USB_DEVICE_PORT_2; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - Exchange::IUSBDevice::USBDevice actual_usbDevice2 = {0}; - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice2); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice2.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice2.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice2.deviceName, std::string("101/002")); - ASSERT_EQ(actual_usbDevice2.devicePath, std::string("/dev/sdb")); - - /* Mock for Device List, 2 Devices */ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 2; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - /* Call GetDeviceList method */ - TEST_LOG("Getting DeviceList Values"); - status = m_usbdeviceplugin->GetDeviceList(devices); - EXPECT_EQ(status,Core::ERROR_NONE); - - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - ASSERT_TRUE(devices != nullptr); - ASSERT_TRUE(2 == devices->Count()); /* Verify device count */ - - /* Verify device 1 details */ - ASSERT_TRUE(devices->Next(actual_usbDevice_dev_list)); - ASSERT_EQ(actual_usbDevice_dev_list.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice_dev_list.devicePath, std::string("/dev/sda")); - - /* Verify device 2 details */ - ASSERT_TRUE(devices->Next(actual_usbDevice_dev_list)); - ASSERT_EQ(actual_usbDevice_dev_list.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice_dev_list.deviceName, std::string("101/002")); - ASSERT_EQ(actual_usbDevice_dev_list.devicePath, std::string("/dev/sdb")); - devices->Release(); - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* HotPlug Deattach Device 2 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_2; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_2; - dev.port_number = MOCK_USB_DEVICE_PORT_2; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("101/002")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sdb")); - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - - TEST_LOG("** Test Case: getDeviceListUsingWithMultipleMassStorageUSBComRpcConnectionSuccessCase Ended **"); -} - -/* Test Case for bindDriver Method - * Activating USB Device Plugin, - * Setting Mocks for simulating the plugged in event - * Setting Mocks to send the usb details like serial number, device address, port and bus numbers - * Setting Mocks to send the port and bus numbers, open device, attach kernl libusb functions - * Sending Plugged In event and Verify USBDevice struct with Valid device details - * Calling the bindDriver function with deviceName and verify whether it is sucessed - * Deactivating the USB Device -*/ -TEST_F(USBDeviceTest, bindDriverComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - - TEST_LOG("** Test Case: bindDriverComRpcConnectionSuccessCase Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* Mock for Device List, 1 Device */ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - /* Call bindDriver method */ - TEST_LOG("call BindDriver"); - std::string deviceName = std::string("100/001"); - status = m_usbdeviceplugin->BindDriver(deviceName); - EXPECT_EQ(status,Core::ERROR_NONE); - - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - - TEST_LOG("** Test Case: bindDriverComRpcConnectionSuccessCase Ended **"); -} - -/* Test Case for UnbindDriver Method - * Activating USB Device Plugin, - * Setting Mocks for simulating the plugged in event - * Setting Mocks to send the usb details like serial number, device address, port and bus numbers - * Setting Mocks to send the port and bus numbers, open device, attach kernl libusb functions - * Sending Plugged In event and Verify USBDevice struct with Valid device details - * Calling the unbindDriver function with deviceName and verify whether it is sucessed - * Deactivating the USB Device -*/ -TEST_F(USBDeviceTest, unbindDriverComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - - TEST_LOG("** Test Case: unbindDriverComRpcConnectionSuccessCase Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - /* Mock for Device List, 1 Device */ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_kernel_driver_active(::testing::_, ::testing::_)) - .WillOnce( - []() { - return 1; /* Sending driver is active */ - }); - - /* Call UnbindDriver method */ - TEST_LOG("call UnbindDriver"); - std::string deviceName = std::string("100/001"); - status = m_usbdeviceplugin->UnbindDriver(deviceName); - EXPECT_EQ(status,Core::ERROR_NONE); - - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - - TEST_LOG("** Test Case: unbindDriverComRpcConnectionSuccessCase Ended **"); -} -TEST_F(USBDeviceTest, getDeviceInfoComRpcConnectionSuccessCase) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - struct libusb_config_descriptor *temp_config_desc = nullptr; - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Started **"); - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - return len; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = 1; - desc->iProduct = 2; - desc->iSerialNumber = 3; - return LIBUSB_SUCCESS; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([&temp_config_desc](libusb_device* pDev, struct libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - if (nullptr == *config_desc) - { - std::cout << "malloc failed"; - return (int)1; - } - else - { - temp_config_desc = *config_desc; - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - } - return (int)LIBUSB_SUCCESS; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if ( desc_index == 0 ) - { - data[0] = 4; - data[3] = 0x04; - data[2] = 0x09; - } - else if ( desc_index == 1 /* Manufacturer */ ) - { - const char *buf = MOCK_USB_DEVICE_MANUFACTURER; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - else if ( desc_index == 2 /* ProductID */ ) - { - const char *buf = MOCK_USB_DEVICE_PRODUCT; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - else if ( desc_index == 3 /* SerialNumber */ ) - { - const char *buf = MOCK_USB_DEVICE_SERIAL_NO; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - return (int)data[0]; - }); - TEST_LOG("call GetDeviceInfo"); - std::string deviceName = std::string("100/001"); - Exchange::IUSBDevice::USBDeviceInfo resultItem{}; - status = m_usbdeviceplugin->GetDeviceInfo(deviceName, resultItem); - EXPECT_EQ(status,Core::ERROR_NONE); - - EXPECT_EQ(resultItem.deviceStatus,Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE); - EXPECT_EQ(resultItem.numLanguageIds, 1); - EXPECT_EQ(resultItem.productInfo1.languageId, 0x0409); - EXPECT_TRUE(strcmp(resultItem.productInfo1.serialNumber.c_str(), MOCK_USB_DEVICE_SERIAL_NO)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.manufacturer.c_str(), MOCK_USB_DEVICE_MANUFACTURER)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.product.c_str(), MOCK_USB_DEVICE_PRODUCT)== 0); - - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - if (nullptr != temp_config_desc) - { - free(temp_config_desc); - } - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Ended **"); -} - -TEST_F(USBDeviceTest, getDeviceInfoComRpcConnectionSuccessCase_ascii) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - struct libusb_config_descriptor *temp_config_desc = nullptr; - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase_ascii Started **"); - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - return len; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = 1; - desc->iProduct = 2; - desc->iSerialNumber = 3; - return LIBUSB_SUCCESS; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([&temp_config_desc](libusb_device* pDev, struct libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - if (nullptr == *config_desc) - { - std::cout << "malloc failed"; - return (int)1; - } - else - { - temp_config_desc = *config_desc; - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - } - return (int)LIBUSB_SUCCESS; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - if ( desc_index == 0 ) - { - data[0] = 4; - } - else{ - return -1; - } - }); - - - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor_ascii(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length) { - const char* descriptor = nullptr; - - // Assign appropriate string based on descriptor index - if (desc_index == 1) { - descriptor = MOCK_USB_DEVICE_MANUFACTURER; - } else if (desc_index == 2) { - descriptor = MOCK_USB_DEVICE_PRODUCT; - } else if (desc_index == 3) { - descriptor = MOCK_USB_DEVICE_SERIAL_NO; - } else { - return -1; - } - - int strLength = strlen(descriptor); - if (strLength >= length) { - return -1; - } - - strncpy(reinterpret_cast(data), descriptor, length); - TEST_LOG("ascii oncall"); - return strLength; - }); - - TEST_LOG("call GetDeviceInfo"); - std::string deviceName = std::string("100/001"); - Exchange::IUSBDevice::USBDeviceInfo resultItem{}; - status = m_usbdeviceplugin->GetDeviceInfo(deviceName, resultItem); - EXPECT_EQ(status,Core::ERROR_NONE); - EXPECT_EQ(resultItem.deviceStatus,Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE); - EXPECT_EQ(resultItem.numLanguageIds, 1); - // EXPECT_EQ(resultItem.productInfo1.languageId, 0x0409); - EXPECT_TRUE(strcmp(resultItem.productInfo1.serialNumber.c_str(), MOCK_USB_DEVICE_SERIAL_NO)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.manufacturer.c_str(), MOCK_USB_DEVICE_MANUFACTURER)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.product.c_str(), MOCK_USB_DEVICE_PRODUCT)== 0); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - if (nullptr != temp_config_desc) - { - free(temp_config_desc); - } - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Ended **"); -} - -TEST_F(USBDeviceTest, getDeviceInfoComRpcConnection_libusb_strerror) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - struct libusb_config_descriptor *temp_config_desc = nullptr; - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase_ascii Started **"); - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - return len; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = 1; - desc->iProduct = 2; - desc->iSerialNumber = 3; - return LIBUSB_SUCCESS; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([&temp_config_desc](libusb_device* pDev, struct libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - if (nullptr == *config_desc) - { - std::cout << "malloc failed"; - return (int)1; - } - else - { - temp_config_desc = *config_desc; - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - } - return (int)LIBUSB_SUCCESS; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - if ( desc_index == 0 ) - { - data[0] = 4; - } - else{ - return -1; - } - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor_ascii(::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length) { - TEST_LOG("ascii oncall failure case"); - return -1; // Simulate failure - }); - - TEST_LOG("call GetDeviceInfo"); - std::string deviceName = std::string("100/001"); - Exchange::IUSBDevice::USBDeviceInfo resultItem{}; - status = m_usbdeviceplugin->GetDeviceInfo(deviceName, resultItem); - EXPECT_EQ(status,Core::ERROR_NONE); - EXPECT_EQ(resultItem.deviceStatus,Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE); - EXPECT_EQ(resultItem.numLanguageIds, 1); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - if (nullptr != temp_config_desc) - { - free(temp_config_desc); - } - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_MASS_STORAGE); - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Ended **"); -} - - -TEST_F(USBDeviceTest, getDeviceInfoComRpcConnection_InterfaceDescriptor) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBDevice_StateInvalid; - Exchange::IUSBDevice::USBDevice actual_usbDevice = {0}; - struct libusb_config_descriptor *temp_config_desc = nullptr; - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Started **"); - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBDeviceInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBDevice"); - } - else - { - ASSERT_TRUE(m_controller_usbdevice!= nullptr); - if (m_controller_usbdevice) - { - ASSERT_TRUE(m_usbdeviceplugin!= nullptr); - if (m_usbdeviceplugin) - { - std::string message; - JsonObject expected_status; - StrictMock async_handler; - uint32_t return_value = Core::ERROR_GENERAL; - JSONRPC::LinkType jsonrpc(USBDEVICE_CALLSIGN, USBDEVICEL2TEST_CALLSIGN); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedIn"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedIn(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - return_value = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDevicePluggedOut"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDevicePluggedOut(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, return_value); - - m_usbdeviceplugin->Register(¬ification); - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_PER_INTERFACE); - ON_CALL(*p_libUSBApiImplMock, libusb_get_config_descriptor(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device *dev, int index, struct libusb_config_descriptor **config) { - TEST_LOG("entered oncall "); - // Allocate memory for the config descriptor - libusb_config_descriptor *mockConfig = new libusb_config_descriptor; - - // Set only bNumInterfaces - mockConfig->bNumInterfaces = 1; - - // Allocate space for the interface array - libusb_interface *mockInterfaces = new libusb_interface[1]; - - // Allocate space for altsetting - libusb_interface_descriptor *mockInterfaceDesc = new libusb_interface_descriptor[1]; - - // Fill the interface descriptor - mockInterfaceDesc[0].bInterfaceClass = LIBUSB_CLASS_MASS_STORAGE; - mockInterfaceDesc[0].bInterfaceSubClass = 0x08; - - // Fill the interface structure - mockInterfaces[0].num_altsetting = 1; - mockInterfaces[0].altsetting = mockInterfaceDesc; - - // Assign interfaces array (cast away const) - mockConfig->interface = const_cast(mockInterfaces); - - // Assign the pointer to config - *config = mockConfig; - - return LIBUSB_SUCCESS; - }); - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedIn(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedIn, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedIn); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - return len; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_PER_INTERFACE; - desc->bDeviceClass = LIBUSB_CLASS_PER_INTERFACE; - desc->idVendor = 0x1234; - desc->idProduct = 0x5678; - desc->iManufacturer = 1; - desc->iProduct = 2; - desc->iSerialNumber = 3; - return LIBUSB_SUCCESS; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_config_descriptor(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device *dev, int index, struct libusb_config_descriptor **config) { - TEST_LOG("entered oncall "); - // Allocate memory for the config descriptor - libusb_config_descriptor *mockConfig = new libusb_config_descriptor; - - // Set only bNumInterfaces - mockConfig->bNumInterfaces = 1; - - // Allocate space for the interface array - libusb_interface *mockInterfaces = new libusb_interface[1]; - - // Allocate space for altsetting - libusb_interface_descriptor *mockInterfaceDesc = new libusb_interface_descriptor[1]; - - // Fill the interface descriptor - mockInterfaceDesc[0].bInterfaceClass = LIBUSB_CLASS_MASS_STORAGE; - mockInterfaceDesc[0].bInterfaceSubClass = 0x08; - - // Fill the interface structure - mockInterfaces[0].num_altsetting = 1; - mockInterfaces[0].altsetting = mockInterfaceDesc; - - // Assign interfaces array (cast away const) - mockConfig->interface = const_cast(mockInterfaces); - - // Assign the pointer to config - *config = mockConfig; - - return LIBUSB_SUCCESS; - }); - - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_active_config_descriptor(::testing::_, ::testing::_)) - .WillByDefault([&temp_config_desc](libusb_device* pDev, struct libusb_config_descriptor** config_desc) { - *config_desc = (libusb_config_descriptor *)malloc(sizeof(libusb_config_descriptor)); - if (nullptr == *config_desc) - { - std::cout << "malloc failed"; - return (int)1; - } - else - { - temp_config_desc = *config_desc; - (*config_desc)->bmAttributes = LIBUSB_CONFIG_ATT_BUS_POWERED; - } - return (int)LIBUSB_SUCCESS; - }); - ON_CALL(*p_libUSBApiImplMock, libusb_get_string_descriptor(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device_handle *dev_handle, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) { - data[1] = LIBUSB_DT_STRING; - if ( desc_index == 0 ) - { - data[0] = 4; - data[3] = 0x04; - data[2] = 0x09; - } - else if ( desc_index == 1 /* Manufacturer */ ) - { - const char *buf = MOCK_USB_DEVICE_MANUFACTURER; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - else if ( desc_index == 2 /* ProductID */ ) - { - const char *buf = MOCK_USB_DEVICE_PRODUCT; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - else if ( desc_index == 3 /* SerialNumber */ ) - { - const char *buf = MOCK_USB_DEVICE_SERIAL_NO; - int buffer_len = strlen(buf) * 2,j = 0,index=2; - memset(&data[2],0,length-2); - while((data[index] = buf[j++]) != '\0') - { - index+=2; - } - data[0] = buffer_len+2; - } - return (int)data[0]; - }); - TEST_LOG("call GetDeviceInfo"); - std::string deviceName = std::string("100/001"); - Exchange::IUSBDevice::USBDeviceInfo resultItem{}; - status = m_usbdeviceplugin->GetDeviceInfo(deviceName, resultItem); - EXPECT_EQ(status,Core::ERROR_NONE); - EXPECT_EQ(resultItem.deviceStatus,Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE); - EXPECT_EQ(resultItem.numLanguageIds, 1); - EXPECT_EQ(resultItem.productInfo1.languageId, 0x0409); - EXPECT_TRUE(strcmp(resultItem.productInfo1.serialNumber.c_str(), MOCK_USB_DEVICE_SERIAL_NO)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.manufacturer.c_str(), MOCK_USB_DEVICE_MANUFACTURER)== 0); - EXPECT_TRUE(strcmp(resultItem.productInfo1.product.c_str(), MOCK_USB_DEVICE_PRODUCT)== 0); - if (status != Core::ERROR_NONE) - { - std::string errorMsg = "COM-RPC returned error " + std::to_string(status) + " (" + std::string(Core::ErrorToString(status)) + ")"; - TEST_LOG("Err: %s", errorMsg.c_str()); - } - if (nullptr != temp_config_desc) - { - free(temp_config_desc); - } - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1,LIBUSB_CLASS_PER_INTERFACE); - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"device\":{\"deviceClass\":8,\"deviceSubclass\":8,\"deviceName\":\"100\\/001\",\"devicePath\":\"\\/dev\\/sda\"}}"; - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDevicePluggedOut(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBDevice_onDevicePluggedOut, actual_usbDevice); - EXPECT_TRUE(signalled & USBDevice_onDevicePluggedOut); - ASSERT_EQ(actual_usbDevice.deviceClass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceSubclass, LIBUSB_CLASS_MASS_STORAGE); - ASSERT_EQ(actual_usbDevice.deviceName, std::string("100/001")); - ASSERT_EQ(actual_usbDevice.devicePath, std::string("/dev/sda")); - m_usbdeviceplugin->Unregister(¬ification); - m_usbdeviceplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedIn")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDevicePluggedOut")); - } - else - { - TEST_LOG("m_usbdeviceplugin is NULL"); - } - m_controller_usbdevice->Release(); - } - else - { - TEST_LOG("m_controller_usbdevice is NULL"); - } - } - TEST_LOG("** Test Case: getDeviceInfoComRpcConnectionSuccessCase Ended **"); -} - - diff --git a/Tests/L2Tests/tests/UsbMassStorage_L2Test.cpp b/Tests/L2Tests/tests/UsbMassStorage_L2Test.cpp deleted file mode 100755 index d941d97..0000000 --- a/Tests/L2Tests/tests/UsbMassStorage_L2Test.cpp +++ /dev/null @@ -1,1659 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include "L2Tests.h" -#include "L2TestsMock.h" -#include -#include -#include -#include -#include - -#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//extern "C" int __real_open(const char* pathname, int flags,int mode=0); - -class AsyncHandlerMock_UsbMassStorage -{ - public: - AsyncHandlerMock_UsbMassStorage() - { - } - MOCK_METHOD(void, OnDeviceMounted, (const Core::JSON::Container& eventPayload)); - MOCK_METHOD(void, OnDeviceUnmounted,(const Core::JSON::Container& eventPayload)); -}; - -#define JSON_TIMEOUT (45000) -#define MOUNT_PATH "/tmp/media/usb" - -#define USBDEVICE_CALLSIGN _T("org.rdk.UsbDevice") -#define USBDEVICEL2TEST_CALLSIGN _T("L2tests.1") - -#define USBMASSSTORAGE_CALLSIGN _T("org.rdk.UsbMassStorage") -#define USBMASSSTORAGEL2TEST_CALLSIGN _T("L2tests.1") - - -#define MOCK_USB_DEVICE_BUS_NUMBER_1 100 -#define MOCK_USB_DEVICE_ADDRESS_1 001 -#define MOCK_USB_DEVICE_PORT_1 123 - -#define MOCK_USB_DEVICE_BUS_NUMBER_2 101 -#define MOCK_USB_DEVICE_ADDRESS_2 002 -#define MOCK_USB_DEVICE_PORT_2 124 - -using ::testing::NiceMock; -using namespace WPEFramework; -using testing::StrictMock; -using ::WPEFramework::Exchange::IUSBMassStorage; - -typedef enum : uint32_t { - USBMassStorage_OnDeviceMounted= 0x00000001, - USBMassStorage_OnDeviceUnmounted= 0x00000002, - USBMassStorage_StateInvalid = 0x00000000 - -}USBMassStorageL2test_async_events_t; - -class USBMassStorageNotificationHandler : public Exchange::IUSBMassStorage::INotification { - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - std::vector m_usb_mass_storage; - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IUSBMassStorage::INotification) - END_INTERFACE_MAP - - public: - USBMassStorageNotificationHandler(){} - ~USBMassStorageNotificationHandler(){} - - void OnDeviceMounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo ,Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) override{ - TEST_LOG("onDeviceMounted event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("onDeviceMounted received deviceInfo.deviceName: %s deviceInfo.devicePath: %s", - deviceInfo.deviceName.c_str(), - deviceInfo.devicePath.c_str()); - - m_event_signalled |= USBMassStorage_OnDeviceMounted; - - if (mountPoints == nullptr) { - TEST_LOG("MountPoints_1 is null"); - return; - } - - TEST_LOG("Iterating over mount points %d", mountPoints->Count()); - - Exchange::IUSBMassStorage::USBStorageMountInfo resultItem{}; - int count = 0; - mountPoints->Reset(0); - while (mountPoints->Next(resultItem)) { - TEST_LOG("Next called."); - TEST_LOG("Partition Name: %s", resultItem.partitionName.c_str()); - TEST_LOG("Mount Flags: %d", resultItem.mountFlags); - TEST_LOG("Mount Path: %s", resultItem.mountPath.c_str()); - m_usb_mass_storage.push_back(resultItem); - count ++; - - } - - if (count == 0) { - TEST_LOG("No mount points found."); - } - - m_condition_variable.notify_one(); - } - - void OnDeviceUnmounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo ,Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) override{ - TEST_LOG("onDeviceUnmounted event triggered ***\n"); - std::unique_lock lock(m_mutex); - - TEST_LOG("onDeviceUnmounted received"); - - /* Notify the requester thread. */ - m_event_signalled |= USBMassStorage_OnDeviceUnmounted; - - Exchange::IUSBMassStorage::USBStorageMountInfo resultItem{}; - mountPoints->Reset(0); - while (mountPoints->Next(resultItem)) { - } - m_usb_mass_storage.push_back(resultItem); - m_condition_variable.notify_one(); - } - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, USBMassStorageL2test_async_events_t expected_status, Exchange::IUSBMassStorage::USBStorageMountInfo* actual_mountPoints) - { - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = USBMassStorage_StateInvalid; - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - if (actual_mountPoints) { - size_t count = m_usb_mass_storage.size(); - for (size_t i = 0; i < count; ++i) { - actual_mountPoints[i] = m_usb_mass_storage[i]; - } - } - - m_event_signalled = USBMassStorage_StateInvalid; - return signalled; - } -}; - -class USBMassStorageTest : public L2TestMocks { -protected: - virtual ~USBMassStorageTest() override; - -protected: - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceAttached = nullptr; - libusb_hotplug_callback_fn libUSBHotPlugCbDeviceDetached = nullptr; - libusb_hotplug_callback_fn libUSBHotPlugCbDevice = nullptr; - - public: - USBMassStorageTest(); - - uint32_t WaitForRequestStatus(uint32_t timeout_ms, USBMassStorageL2test_async_events_t expected_status); - uint32_t CreateUSBMassStorageInterfaceObjectUsingComRPCConnection(); - void Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address); - void Mock_SetSerialNumberInUSBDevicePath(); - private: - /** @brief Mutex */ - std::mutex m_mutex; - - /** @brief Condition variable */ - std::condition_variable m_condition_variable; - - /** @brief Event signalled flag */ - uint32_t m_event_signalled; - - protected: - /** @brief Pointer to the IShell interface */ - PluginHost::IShell *m_controller_usbmassstorage; - - /** @brief Pointer to the IUSBMassStorage interface */ - Exchange::IUSBMassStorage *m_usbmassstorageplugin; -}; - -USBMassStorageTest:: USBMassStorageTest():L2TestMocks() -{ - Core::JSONRPC::Message message; - string response; - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Test Constructor"); - - ON_CALL(*p_libUSBApiImplMock, libusb_hotplug_register_callback(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](libusb_context *ctx, int events, int flags, int vendor_id, int product_id, int dev_class, - libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *callback_handle) { - if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == events) { - libUSBHotPlugCbDeviceAttached = cb_fn; - *callback_handle = 1; - } - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == events) { - libUSBHotPlugCbDeviceDetached = cb_fn; - *callback_handle = 2; - } - if (LIBUSB_HOTPLUG_EVENT_DEVICE == events) { - libUSBHotPlugCbDevice = cb_fn; - *callback_handle = 3; - } - return LIBUSB_SUCCESS; - })); - - TEST_LOG("Activate plugins"); - - /* Activate plugin in constructor */ - status = ActivateService("org.rdk.UsbDevice"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = ActivateService("org.rdk.UsbMassStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); -} - -USBMassStorageTest::~USBMassStorageTest() -{ - uint32_t status = Core::ERROR_GENERAL; - - TEST_LOG("Test Destructor"); - - ON_CALL(*p_libUSBApiImplMock, libusb_hotplug_deregister_callback(::testing::_, ::testing::_)) - .WillByDefault(::testing::Invoke( - [&](libusb_context *ctx, libusb_hotplug_callback_handle callback_handle) { - // Check the callback handle to determine which callback to deregister - if (callback_handle == 1) { - libUSBHotPlugCbDeviceAttached = nullptr; // Deregister the "device arrived" callback - } else if (callback_handle == 2) { - libUSBHotPlugCbDeviceDetached = nullptr; // Deregister the "device left" callback - }else if (callback_handle == 3) { - libUSBHotPlugCbDevice = nullptr; // Deregister the "device left" callback - } - // No return value needed as function returns void - })); - - TEST_LOG("DeActivate USBDevice plugin"); - - status = DeactivateService("org.rdk.UsbMassStorage"); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = DeactivateService("org.rdk.UsbDevice"); - EXPECT_EQ(Core::ERROR_NONE, status); - sleep(5); - -} - -uint32_t USBMassStorageTest::WaitForRequestStatus(uint32_t timeout_ms, USBMassStorageL2test_async_events_t expected_status) -{ - std::unique_lock lock(m_mutex); - auto now = std::chrono::system_clock::now(); - std::chrono::milliseconds timeout(timeout_ms); - uint32_t signalled = USBMassStorage_StateInvalid; - - while (!(expected_status & m_event_signalled)) - { - if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) - { - TEST_LOG("Timeout waiting for request status event"); - break; - } - } - - signalled = m_event_signalled; - return signalled; -} - -void USBMassStorageTest::Mock_SetDeviceDesc(uint8_t bus_number, uint8_t device_address) -{ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillByDefault( - [bus_number, device_address](libusb_device *dev, struct libusb_device_descriptor *desc) { - if ((bus_number == dev->bus_number) && - (device_address == dev->device_address)) - { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - } - return LIBUSB_SUCCESS; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillByDefault(::testing::Return(device_address)); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillByDefault(::testing::Return(bus_number)); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillByDefault([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - if (device_address == MOCK_USB_DEVICE_ADDRESS_1) - { - std::string vendorFileName = "/tmp/block/sda/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "Generic" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sda/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Flash Disk" << std::endl; - outModelStream.close(); - } - - if (device_address == MOCK_USB_DEVICE_ADDRESS_2) - { - std::string vendorFileName = "/tmp/block/sdb/device/vendor"; - std::ofstream outVendorStream(vendorFileName); - - if (!outVendorStream) { - TEST_LOG("Error opening file for writing!"); - } - outVendorStream << "JetFlash" << std::endl; - outVendorStream.close(); - - std::string modelFileName = "/tmp/block/sdb/device/model"; - std::ofstream outModelStream(modelFileName); - - if (!outModelStream) { - TEST_LOG("Error opening file for writing!"); - } - outModelStream << "Transcend_16GB" << std::endl; - outModelStream.close(); - } -} - -void USBMassStorageTest::Mock_SetSerialNumberInUSBDevicePath() -{ - std::string serialNumFileName1 = "/tmp/bus/usb/devices/100-123/serial"; - std::ofstream serialNumOutFile1(serialNumFileName1); - - if (!serialNumOutFile1) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile1 << "B32FD507" << std::endl; - serialNumOutFile1.close(); - - std::string serialNumFileName2 = "/tmp/bus/usb/devices/101-124/serial"; - std::ofstream serialNumOutFile2(serialNumFileName2); - - if (!serialNumOutFile2) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFile2<< "UEUIRCXT" << std::endl; - serialNumOutFile2.close(); - - std::string serialNumFileSda = "/dev/sda"; - std::ofstream serialNumOutFileSda(serialNumFileSda); - - if (!serialNumOutFileSda) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFileSda << "B32FD507 100-123" << std::endl; - serialNumOutFileSda.close(); - - - std::string serialNumFileSdb = "/dev/sdb"; - std::ofstream serialNumOutFileSdb(serialNumFileSdb); - - if (!serialNumOutFileSdb) { - TEST_LOG("Error opening file for writing!"); - } - serialNumOutFileSdb << "UEUIRCXT 101-124" << std::endl; - serialNumOutFileSdb.close(); -} - -uint32_t USBMassStorageTest::CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() -{ - uint32_t return_value = Core::ERROR_GENERAL; - Core::ProxyType> Engine_USBMassStorage; - Core::ProxyType Client_USBMassStorage; - - TEST_LOG("Creating Engine_USBMassStorage"); - Engine_USBMassStorage = Core::ProxyType>::Create(); - Client_USBMassStorage = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(Engine_USBMassStorage)); - - TEST_LOG("Creating Engine_USBMassStorage Announcements"); -#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) - Engine_USBMassStorage->Announcements(mClient_USBMassStorage->Announcement()); -#endif - if (!Client_USBMassStorage.IsValid()) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - m_controller_usbmassstorage = Client_USBMassStorage->Open(USBMASSSTORAGE_CALLSIGN, ~0, 3000); - if (m_controller_usbmassstorage) - { - m_usbmassstorageplugin = m_controller_usbmassstorage->QueryInterface(); - return_value = Core::ERROR_NONE; - } - } - return return_value; -} - -/** - * @brief Compare two request status objects - * - * @param[in] data Expected value - * @return true if the argument and data match, false otherwise - */ -MATCHER_P(MatchRequestStatus, data, "") -{ - bool match = true; - std::string expected; - std::string actual; - - data.ToString(expected); - arg.ToString(actual); - TEST_LOG(" rec = %s, arg = %s",expected.c_str(),actual.c_str()); - EXPECT_STREQ(expected.c_str(),actual.c_str()); - - return match; -} - -TEST_F(USBMassStorageTest, comrpc_getpartitionInfo_success) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = {}; - WPEFramework::Exchange::IUSBMassStorage::USBStoragePartitionInfo partitionInfo = {}; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceMounted); - - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statfs* buf) -> int { - // if (buf != nullptr) { - // buf->f_type = 0x565a; - // return 0; - // } - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int flags, mode_t mode) { - TEST_LOG("Inside open mock, calling real open."); - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](int fd, unsigned long request, void* argp) -> int { - if (request == BLKGETSIZE64) { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 *1024; - } - else if (request == BLKGETSIZE) { - *(reinterpret_cast(argp)) = 1024; - } - else if (request == BLKSSZGET) { - *(reinterpret_cast(argp)) = 512; - } - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - size_t i = 0; - while (!mountPointsArray[i].mountPath.empty()) { - - status = m_usbmassstorageplugin->GetPartitionInfo(mountPointsArray[i].mountPath, partitionInfo); - EXPECT_EQ(status, Core::ERROR_NONE); - - EXPECT_EQ(partitionInfo.fileSystem, WPEFramework::Exchange::IUSBMassStorage::USBStorageFileSystem::VFAT); - EXPECT_EQ(partitionInfo.size, 51200); - EXPECT_EQ(partitionInfo.numSectors, 1024); - EXPECT_EQ(partitionInfo.sectorSize, 512); - EXPECT_EQ(partitionInfo.totalSpace, 4000); - EXPECT_EQ(partitionInfo.usedSpace, 3000); - EXPECT_EQ(partitionInfo.availableSpace, partitionInfo.totalSpace - partitionInfo.usedSpace); - ++i; - } - - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceUnmounted, mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceUnmounted); - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - } - } - TEST_LOG("** Test Case: Ended **"); - -} - -TEST_F(USBMassStorageTest, comrpc_getDeviceListAndMount_success) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = {}; - Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator* deviceInfo = nullptr; - std::string selectedDeviceName; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceMounted); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - const std::string expectedDevicePath = "/dev/sda"; - const std::string expectedDeviceName = "100/001"; - - status = m_usbmassstorageplugin->GetDeviceList(deviceInfo); - EXPECT_EQ(status, Core::ERROR_NONE); - - Exchange::IUSBMassStorage::USBStorageDeviceInfo currentDevice; - while (deviceInfo->Next(currentDevice)) { - EXPECT_FALSE(currentDevice.devicePath.empty()); - EXPECT_FALSE(currentDevice.deviceName.empty()); - - TEST_LOG("Device path: %s, Device name: %s", currentDevice.devicePath.c_str(),currentDevice.deviceName.c_str()); - EXPECT_EQ(currentDevice.devicePath, expectedDevicePath); - EXPECT_EQ(currentDevice.deviceName, expectedDeviceName); - selectedDeviceName = currentDevice.deviceName; - } - status = m_usbmassstorageplugin->GetMountPoints(selectedDeviceName, mountPoints); - EXPECT_EQ(status, Core::ERROR_NONE); - - IUSBMassStorage::USBStorageMountInfo mountInfo; - while (mountPoints->Next(mountInfo)) { - TEST_LOG("Partition Name: %s", mountInfo.partitionName.c_str()); - TEST_LOG("Mount Flags: %d", mountInfo.mountFlags); - TEST_LOG("Mount Path: %s", mountInfo.mountPath.c_str()); - } - - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceUnmounted, mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceUnmounted); - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - - } - - } - - -} - - - -TEST_F(USBMassStorageTest, comrpc_mount_failure) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator* deviceInfo = nullptr; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return -1; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - - EXPECT_FALSE(signalled & USBMassStorage_OnDeviceMounted); - - status = m_usbmassstorageplugin->GetDeviceList(deviceInfo); - EXPECT_EQ(status, Core::ERROR_GENERAL); - - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - } - } -} - -TEST_F(USBMassStorageTest, comrpc_open_failure) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = {}; - WPEFramework::Exchange::IUSBMassStorage::USBStoragePartitionInfo partitionInfo = {}; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return 0; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceMounted); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statfs* buf) -> int { - // if (buf != nullptr) { - // buf->f_type = 0x565a; - // return 0; - // } - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int flags, mode_t mode) { - return -1; - }); - - size_t i =0; - status = m_usbmassstorageplugin->GetPartitionInfo(mountPointsArray[i].mountPath, partitionInfo); - EXPECT_NE(status, Core::ERROR_NONE); - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - } - } - TEST_LOG("** Test Case: Ended **"); -} - -TEST_F(USBMassStorageTest, comrpc_event_default_failure) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator* deviceInfo = nullptr; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - return -1; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE, 0); - - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - } - } -} - -TEST_F(USBMassStorageTest, comrpc_unmount_failure) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = {}; - Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator* deviceInfo = nullptr; - std::string selectedDeviceName; - - TEST_LOG("** Test Case Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - m_usbmassstorageplugin->Register(¬ification); - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - TEST_LOG("mount"); - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return -1; - }); - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceMounted); - - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 1; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - const std::string expectedDevicePath = "/dev/sda"; - const std::string expectedDeviceName = "100/001"; - - status = m_usbmassstorageplugin->GetDeviceList(deviceInfo); - EXPECT_EQ(status, Core::ERROR_NONE); - - Exchange::IUSBMassStorage::USBStorageDeviceInfo currentDevice; - while (deviceInfo->Next(currentDevice)) { - EXPECT_FALSE(currentDevice.devicePath.empty()); - EXPECT_FALSE(currentDevice.deviceName.empty()); - - TEST_LOG("Device path: %s, Device name: %s", currentDevice.devicePath.c_str(),currentDevice.deviceName.c_str()); - EXPECT_EQ(currentDevice.devicePath, expectedDevicePath); - EXPECT_EQ(currentDevice.deviceName, expectedDeviceName); - selectedDeviceName = currentDevice.deviceName; - } - - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceUnmounted, mountPointsArray); - - EXPECT_FALSE(signalled & USBMassStorage_OnDeviceUnmounted); - - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - } - } - -} -#if 0 -TEST_F(USBMassStorageTest, comrpc_Multiple_getDeviceListAndMount_success) -{ - uint32_t status = Core::ERROR_GENERAL; - Core::Sink notification; - uint32_t signalled = USBMassStorage_StateInvalid; - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = {}; - Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator* deviceInfo = nullptr; - std::string selectedDeviceName; - - TEST_LOG("** Test Case: getDeviceListUsingWithMultipleMassStorageUSBComRpcConnectionSuccessCase Started **"); - - Mock_SetSerialNumberInUSBDevicePath(); - if (CreateUSBMassStorageInterfaceObjectUsingComRPCConnection() != Core::ERROR_NONE) - { - TEST_LOG("Invalid Client_USBMassStorage"); - } - else - { - ASSERT_TRUE(m_controller_usbmassstorage!= nullptr); - if (m_controller_usbmassstorage) - { - ASSERT_TRUE(m_usbmassstorageplugin!= nullptr); - - if (m_usbmassstorageplugin) - { - std::string message; - - StrictMock async_handler; - JSONRPC::LinkType jsonrpc(USBMASSSTORAGE_CALLSIGN, USBMASSSTORAGEL2TEST_CALLSIGN); - JsonObject expected_status; - - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDeviceMounted"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDeviceMounted(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - status = jsonrpc.Subscribe(JSON_TIMEOUT, - _T("onDeviceUnmounted"), - [this, &async_handler](const Core::JSON::Container &eventPayload) { - async_handler.OnDeviceUnmounted(eventPayload); - }); - EXPECT_EQ(Core::ERROR_NONE, status); - - m_usbmassstorageplugin->Register(¬ification); - - - /* HotPlug Attach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - libusb_device dev = {0}; - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - static int index = 1; - - EXPECT_CALL(*p_wrapsImplMock, stat(::testing::_, ::testing::_)) - .WillRepeatedly([](const std::string& path, struct stat* info) { - std::string expectedPath = MOUNT_PATH + std::to_string(index); - TEST_LOG("expectedPath =%s, path =%s",expectedPath.c_str(), path.c_str()); - - if (path == expectedPath) { - index++; - return -1; - } - info->st_mode = S_IFDIR; - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, mkdir(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, mode_t mode) { - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, mount(::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void* data) { - TEST_LOG("mount"); - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statfs* buf) -> int { - // if (buf != nullptr) { - // buf->f_type = 0x565a; - // return 0; - // } - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, statvfs(::testing::_, ::testing::_)) - .WillRepeatedly([](const char* path, struct statvfs* stat) -> int { - if (stat != nullptr) { - stat->f_blocks = 1024000; - stat->f_frsize = 4096; - stat->f_bfree = 256000; - return 0; - } - return -1; - }); - - EXPECT_CALL(*p_wrapsImplMock, open(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](const char* pathname, int flags, mode_t mode) { - TEST_LOG("Inside open mock, calling real open."); - return 0; - }); - - - EXPECT_CALL(*p_wrapsImplMock, ioctl(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](int fd, unsigned long request, void* argp) -> int { - if (request == BLKGETSIZE64) { - *(reinterpret_cast(argp)) = 50ULL * 1024 * 1024 *1024; - } - else if (request == BLKGETSIZE) { - *(reinterpret_cast(argp)) = 1024; - } - else if (request == BLKSSZGET) { - *(reinterpret_cast(argp)) = 512; - } - return 0; - }); - - EXPECT_CALL(*p_wrapsImplMock, umount(::testing::_)) - .WillRepeatedly([](const char* path) { - return 0; - }); - - const size_t maxMountPointsSize = 10; - Exchange::IUSBMassStorage::USBStorageMountInfo* mountPointsArray = new Exchange::IUSBMassStorage::USBStorageMountInfo[maxMountPointsSize]; - - message = "{\"mountPoints\":[{\"partitionName\":\"\\/dev\\/sda1\",\"mountFlags\":\"READ_WRITE\",\"mountPath\":\"\\/tmp\\/media\\/usb1\",\"fileSystem\":\"VFAT\"},{\"partitionName\":\"\\/dev\\/sda2\",\"mountFlags\":\"READ_WRITE\",\"mountPath\":\"\\/tmp\\/media\\/usb2\",\"fileSystem\":\"VFAT\"}],\"deviceinfo\":{\"devicePath\":\"\\/dev\\/sda\",\"deviceName\":\"100\\/001\"}}"; - - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDeviceMounted(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceMounted,mountPointsArray); - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceMounted); - - - /* HotPlug Attach Device 2 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_2; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_2; - dev.port_number = MOCK_USB_DEVICE_PORT_2; - - libUSBHotPlugCbDeviceAttached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0); - - - /* Mock for Device List, 2 Devices */ - ON_CALL(*p_libUSBApiImplMock, libusb_get_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_context *ctx, libusb_device ***list) { - struct libusb_device **ret = nullptr; - ssize_t len = 2; - - ret = (struct libusb_device **)malloc(len * sizeof(struct libusb_device *)); - - if (nullptr == ret) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - uint8_t bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - uint8_t device_address = MOCK_USB_DEVICE_ADDRESS_1; - uint8_t port_number = MOCK_USB_DEVICE_PORT_1; - - for (int index = 0; index < len; ++index) - { - ret[index] = (struct libusb_device *)malloc(sizeof(struct libusb_device)); - - if (nullptr == ret[index]) - { - std::cout << "malloc failed"; - len = 0; - } - else - { - ret[index]->bus_number = bus_number; - ret[index]->device_address = device_address; - ret[index]->port_number = port_number; - - bus_number += 1; - device_address += 1; - port_number += 1; - } - } - *list = ret; - } - - return len; - }); - - ON_CALL(*p_libUSBApiImplMock, libusb_free_device_list(::testing::_, ::testing::_)) - .WillByDefault( - [](libusb_device **list, int unref_devices) { - for (int index = 0; index < 2; ++index) - { - free(list[index]); - } - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_descriptor(::testing::_, ::testing::_)) - .WillRepeatedly( - [](libusb_device *dev, struct libusb_device_descriptor *desc) { - desc->bDeviceSubClass = LIBUSB_CLASS_MASS_STORAGE; - desc->bDeviceClass = LIBUSB_CLASS_MASS_STORAGE; - return LIBUSB_SUCCESS; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_device_address(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->device_address; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_bus_number(::testing::_)) - .WillRepeatedly( - [](libusb_device *dev) { - return dev->bus_number; - }); - - EXPECT_CALL(*p_libUSBApiImplMock, libusb_get_port_numbers(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly([](libusb_device *dev, uint8_t *port_numbers, int port_numbers_len) { - if((nullptr != dev) && (nullptr != port_numbers)) - { - port_numbers[0] = dev->port_number; - return 1; - } - else - { - return 0; - } - }); - - status = m_usbmassstorageplugin->GetDeviceList(deviceInfo); - EXPECT_EQ(status, Core::ERROR_NONE); - - std::vector deviceNames; - Exchange::IUSBMassStorage::USBStorageDeviceInfo currentDevice; - while (deviceInfo->Next(currentDevice)) { - EXPECT_FALSE(currentDevice.devicePath.empty()); - EXPECT_FALSE(currentDevice.deviceName.empty()); - TEST_LOG("Device path: %s, Device name: %s", currentDevice.devicePath.c_str(), currentDevice.deviceName.c_str()); - deviceNames.push_back(currentDevice.deviceName); - } - - for (const auto& deviceName : deviceNames) { - status = m_usbmassstorageplugin->GetMountPoints(deviceName, mountPoints); - // if there are no partitions then no need to check getMountPoints. - if (mountPoints == nullptr) { - EXPECT_EQ(status, Core::ERROR_GENERAL); - } - else - { - EXPECT_EQ(status, Core::ERROR_NONE); - IUSBMassStorage::USBStorageMountInfo mountInfo; - while (mountPoints->Next(mountInfo)) { - TEST_LOG("Partition Name: %s", mountInfo.partitionName.c_str()); - TEST_LOG("Mount Flags: %d", mountInfo.mountFlags); - TEST_LOG("Mount Path: %s", mountInfo.mountPath.c_str()); - - Exchange::IUSBMassStorage::USBStoragePartitionInfo partitionInfo; - status = m_usbmassstorageplugin->GetPartitionInfo(mountInfo.mountPath, partitionInfo); - EXPECT_EQ(status, Core::ERROR_NONE); - - TEST_LOG("Partition Info: FileSystem=%d, Size=%lu, NumSectors=%lu, SectorSize=%lu, TotalSpace=%lu, UsedSpace=%lu, AvailableSpace=%lu", - partitionInfo.fileSystem, partitionInfo.size, partitionInfo.numSectors, - partitionInfo.sectorSize, partitionInfo.totalSpace, - partitionInfo.usedSpace, partitionInfo.availableSpace); - } - } - } - - /* HotPlug Dettach Device 1 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_1, MOCK_USB_DEVICE_ADDRESS_1); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_1; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_1; - dev.port_number = MOCK_USB_DEVICE_PORT_1; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - message = "{\"mountPoints\":[{\"partitionName\":\"\\/dev\\/sda1\",\"mountFlags\":\"READ_WRITE\",\"mountPath\":\"\\/tmp\\/media\\/usb1\",\"fileSystem\":\"VFAT\"},{\"partitionName\":\"\\/dev\\/sda2\",\"mountFlags\":\"READ_WRITE\",\"mountPath\":\"\\/tmp\\/media\\/usb2\",\"fileSystem\":\"VFAT\"}],\"deviceinfo\":{\"devicePath\":\"\\/dev\\/sda\",\"deviceName\":\"100\\/001\"}}"; - - expected_status.FromString(message); - EXPECT_CALL(async_handler, OnDeviceUnmounted(MatchRequestStatus(expected_status))); - - signalled = notification.WaitForRequestStatus(JSON_TIMEOUT, USBMassStorage_OnDeviceUnmounted, mountPointsArray); - - EXPECT_TRUE(signalled & USBMassStorage_OnDeviceUnmounted); - - /* HotPlug Deattach Device 2 Verification */ - Mock_SetDeviceDesc(MOCK_USB_DEVICE_BUS_NUMBER_2, MOCK_USB_DEVICE_ADDRESS_2); - - dev.bus_number = MOCK_USB_DEVICE_BUS_NUMBER_2; - dev.device_address = MOCK_USB_DEVICE_ADDRESS_2; - dev.port_number = MOCK_USB_DEVICE_PORT_2; - - libUSBHotPlugCbDeviceDetached(nullptr, &dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0); - - delete[] mountPointsArray; - m_usbmassstorageplugin->Unregister(¬ification); - m_usbmassstorageplugin->Release(); - - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDeviceMounted")); - jsonrpc.Unsubscribe(JSON_TIMEOUT, _T("onDeviceUnmounted")); - } - else - { - TEST_LOG("m_usbmassstorageplugin is NULL"); - } - m_controller_usbmassstorage->Release(); - - } - - } - -} -#endif - diff --git a/USBDevice/CHANGELOG.md b/USBDevice/CHANGELOG.md deleted file mode 100755 index 9566ca0..0000000 --- a/USBDevice/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/USBDevice/CMakeLists.txt b/USBDevice/CMakeLists.txt deleted file mode 100755 index a9d87e6..0000000 --- a/USBDevice/CMakeLists.txt +++ /dev/null @@ -1,100 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME USBDevice) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_USBDEVICE_AUTOSTART "true" CACHE STRING "Automatically start USBDevice plugin") -set(PLUGIN_USBDEVICE_STARTUPORDER "40" CACHE STRING "To configure startup order of USBDevice plugin") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) -find_package(Boost COMPONENTS system filesystem REQUIRED) - -if (NOT RDK_SERVICE_L2_TEST AND NOT RDK_SERVICES_L1_TEST) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBUSB REQUIRED libusb-1.0) -endif() - -add_library(${MODULE_NAME} SHARED - USBDevice.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -if (NOT RDK_SERVICE_L2_TEST AND NOT RDK_SERVICES_L1_TEST) - target_link_libraries(${MODULE_NAME} - PRIVATE - ${LIBUSB_LIBRARIES}) -endif() - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - USBDeviceImplementation.cpp - Module.cpp) - -include_directories(../helpers) - -if (NOT RDK_SERVICE_L2_TEST AND NOT RDK_SERVICES_L1_TEST) - include_directories(${LIBUSB_INCLUDE_DIRS}) -endif() - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${LIBUSB_LIBRARIES} - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY}) - -if (NOT RDK_SERVICE_L2_TEST AND NOT RDK_SERVICES_L1_TEST) - target_link_libraries(${PLUGIN_IMPLEMENTATION} - PRIVATE - ${LIBUSB_LIBRARIES}) -else (RDK_SERVICE_L2_TEST AND RDK_SERVICES_L1_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST AND RDK_SERVICES_L1_TEST) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) - diff --git a/USBDevice/Module.cpp b/USBDevice/Module.cpp deleted file mode 100755 index 713d4b1..0000000 --- a/USBDevice/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/USBDevice/Module.h b/USBDevice/Module.h deleted file mode 100755 index c02b820..0000000 --- a/USBDevice/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_USBDevice -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/USBDevice/USBDevice.conf.in b/USBDevice/USBDevice.conf.in deleted file mode 100755 index 6631086..0000000 --- a/USBDevice/USBDevice.conf.in +++ /dev/null @@ -1,11 +0,0 @@ -autostart = "@PLUGIN_USBDEVICE_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.UsbDevice" -startuporder = "@PLUGIN_USBDEVICE_STARTUPORDER@" - -configuration = JSON() -rootobject = JSON() - -rootobject.add("mode", "@PLUGIN_USBDEVICE_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) diff --git a/USBDevice/USBDevice.config b/USBDevice/USBDevice.config deleted file mode 100755 index 253516b..0000000 --- a/USBDevice/USBDevice.config +++ /dev/null @@ -1,15 +0,0 @@ -set(autostart ${PLUGIN_USBDEVICE_AUTOSTART}) - -if(PLUGIN_USBDEVICE_STARTUPORDER) -set (startuporder ${PLUGIN_USBDEVICE_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_USBDEVICE_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) - diff --git a/USBDevice/USBDevice.cpp b/USBDevice/USBDevice.cpp deleted file mode 100755 index 73250ea..0000000 --- a/USBDevice/USBDevice.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "USBDevice.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 0 - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register USBDevice module as wpeframework plugin - **/ - SERVICE_REGISTRATION(USBDevice, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - USBDevice::USBDevice() : _service(nullptr), _connectionId(0), _usbDeviceImpl(nullptr), _usbDeviceNotification(this) - { - SYSLOG(Logging::Startup, (_T("USBDevice Constructor"))); - } - - USBDevice::~USBDevice() - { - SYSLOG(Logging::Shutdown, (string(_T("USBDevice Destructor")))); - } - - const string USBDevice::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == _service); - ASSERT(nullptr == _usbDeviceImpl); - ASSERT(0 == _connectionId); - - SYSLOG(Logging::Startup, (_T("USBDevice::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - _service->Register(&_usbDeviceNotification); - _usbDeviceImpl = _service->Root(_connectionId, 5000, _T("USBDeviceImplementation")); - - if(nullptr != _usbDeviceImpl) - { - // Register for notifications - _usbDeviceImpl->Register(&_usbDeviceNotification); - // Invoking Plugin API register to wpeframework - Exchange::JUSBDevice::Register(*this, _usbDeviceImpl); - } - else - { - SYSLOG(Logging::Startup, (_T("USBDevice::Initialize: Failed to initialise USBDevice plugin"))); - message = _T("USBDevice plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void USBDevice::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("USBDevice::Deinitialize")))); - - if (nullptr != _usbDeviceImpl) - { - _usbDeviceImpl->Unregister(&_usbDeviceNotification); - Exchange::JUSBDevice::Unregister(*this); - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED uint32_t result = _usbDeviceImpl->Release(); - - _usbDeviceImpl = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - connection->Terminate(); - connection->Release(); - } - } - - if(nullptr != _service) - { - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - _service->Unregister(&_usbDeviceNotification); - _service->Release(); - _service = nullptr; - } - _connectionId = 0; - SYSLOG(Logging::Shutdown, (string(_T("USBDevice de-initialised")))); - } - - string USBDevice::Information() const - { - SYSLOG(Logging::Shutdown, (string(_T("USBDevice Information")))); - // No additional info to report - return (string()); - } - - void USBDevice::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == _connectionId) - { - SYSLOG(Logging::Shutdown, (string(_T("USBDevice Deactivated")))); - ASSERT(nullptr != _service); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBDevice/USBDevice.h b/USBDevice/USBDevice.h deleted file mode 100755 index 9c1ef6b..0000000 --- a/USBDevice/USBDevice.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include "UtilsLogging.h" -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - - class USBDevice: public PluginHost::IPlugin, public PluginHost::JSONRPC - { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IUSBDevice::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(USBDevice* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IUSBDevice::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override - { - } - - void Deactivated(RPC::IRemoteConnection *connection) override - { - _parent.Deactivated(connection); - } - - void OnDevicePluggedIn(const Exchange::IUSBDevice::USBDevice &device) override - { - LOGINFO("OnDevicePluggedIn"); - Exchange::JUSBDevice::Event::OnDevicePluggedIn(_parent, device); - } - - void OnDevicePluggedOut(const Exchange::IUSBDevice::USBDevice &device) override - { - LOGINFO("OnDevicePluggedOut"); - Exchange::JUSBDevice::Event::OnDevicePluggedOut(_parent, device); - } - - private: - USBDevice& _parent; - }; - - public: - // We do not allow this plugin to be copied !! - USBDevice(const USBDevice&) = delete; - USBDevice& operator=(const USBDevice&) = delete; - - USBDevice(); - virtual ~USBDevice(); - - BEGIN_INTERFACE_MAP(USBDevice) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IUSBDevice, _usbDeviceImpl) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* _service{}; - uint32_t _connectionId{}; - Exchange::IUSBDevice* _usbDeviceImpl{}; - Core::Sink _usbDeviceNotification; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBDevice/USBDeviceImplementation.cpp b/USBDevice/USBDeviceImplementation.cpp deleted file mode 100755 index 5f2abc5..0000000 --- a/USBDevice/USBDeviceImplementation.cpp +++ /dev/null @@ -1,1246 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "USBDeviceImplementation.h" -#include -#include "UtilsJsonRpc.h" -#include -#include "tracing/Logging.h" -#include -#include - -#if defined(RDK_SERVICE_L2_TEST) || defined(RDK_SERVICES_L1_TEST) -#define PLUGIN_USBDEVICE_PATH "/tmp/bus/usb/devices" -#define PLUGIN_USBDEVICE_BLOCKPATH "/tmp/block" -#define PLUGIN_USBDEVICE_BUS_NUM "busnum" -#define PLUGIN_USBDEVICE_DEV_ADDR "devnum" -#else -#define PLUGIN_USBDEVICE_PATH "/sys/bus/usb/devices" -#define PLUGIN_USBDEVICE_BLOCKPATH "/sys/block" -#define PLUGIN_USBDEVICE_BUS_NUM "busnum" -#define PLUGIN_USBDEVICE_DEV_ADDR "devnum" -#endif /* defined(RDK_SERVICE_L2_TEST) || defined(RDK_SERVICES_L1_TEST) */ - -#define PLUGIN_USBDEVICE_DEV_DISK_PATH "/dev/disk/by-id/" -#define PLUGIN_USBDEVICE_VENDOR_PATH "device/vendor" -#define PLUGIN_USBDEVICE_MODEL_PATH "device/model" - -/** -* @brief length of the usb string descriptor header -*/ -#define USB_STRING_DESC_HEADER_LENGTH 2 -namespace WPEFramework { -namespace Plugin { - -SERVICE_REGISTRATION(USBDeviceImplementation, 1, 0); - -USBDeviceImplementation::USBDeviceImplementation() -: _adminLock() -, _libUSBDeviceThread(nullptr) -,_handlingUSBDeviceEvents(false) -{ - LOGINFO("Create USBDeviceImplementation Instance"); - USBDeviceImplementation::instance(this); - - if (Core::ERROR_NONE != libUSBInit()) - { - LOGERR("libUSBInit Failed"); - } -} - -USBDeviceImplementation* USBDeviceImplementation::instance(USBDeviceImplementation *USBDeviceImpl) -{ - static USBDeviceImplementation *USBDeviceImpl_instance = nullptr; - - if (USBDeviceImpl != nullptr) - { - USBDeviceImpl_instance = USBDeviceImpl; - } - - return(USBDeviceImpl_instance); -} - -USBDeviceImplementation::~USBDeviceImplementation() -{ - libUSBClose(); -} - -uint32_t USBDeviceImplementation::libUSBInit(void) -{ - uint32_t status = Core::ERROR_GENERAL; - int retValue = LIBUSB_SUCCESS; - LOGINFO("Entry"); - - retValue = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0); - - if (LIBUSB_SUCCESS != retValue) - { - LOGERR ("failed to initialise libusb: %s\n", libusb_strerror((enum libusb_error)retValue)); - } - else if(!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) - { - LOGERR ("Hotplug capabilities are not supported on this platform\n"); - libusb_exit (NULL); - } - else if (LIBUSB_SUCCESS != (retValue = libusb_hotplug_register_callback(NULL, - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, - 0, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - USBDeviceImplementation::libUSBHotPlugCallbackDeviceAttached, - NULL, - &_hotPlugHandle[0]))) - { - LOGERR ("Error registering libUSBHotPlugCallbackDeviceAttached: %s\n", libusb_strerror((enum libusb_error)retValue)); - libusb_exit (NULL); - } - else if (LIBUSB_SUCCESS != (retValue = libusb_hotplug_register_callback(NULL, - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, - 0, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - USBDeviceImplementation::libUSBHotPlugCallbackDeviceDetached, - NULL, - &_hotPlugHandle[1]))) - { - LOGERR ("Error registering libUSBHotPlugCallbackDeviceDetached: %s\n", libusb_strerror((enum libusb_error)retValue)); - libusb_exit (NULL); - } - else if (nullptr == _libUSBDeviceThread) - { - _handlingUSBDeviceEvents = true; - - _libUSBDeviceThread = new std::thread(&USBDeviceImplementation::libUSBEventsHandlingThread, USBDeviceImplementation::instance()); - - if (nullptr != _libUSBDeviceThread) - { - LOGINFO("libUSBInit Successed"); - status = Core::ERROR_NONE; - } - else - { - LOGERR("libUSBEventsHandlingThread Failed"); - _handlingUSBDeviceEvents = false; - } - } - else - { - LOGINFO("libUSBInit Successed"); - status = Core::ERROR_NONE; - } - - return status; -} - -void USBDeviceImplementation::libUSBClose(void) -{ - _handlingUSBDeviceEvents = false; - - (void)libusb_hotplug_deregister_callback(NULL, _hotPlugHandle[0]); - (void)libusb_hotplug_deregister_callback(NULL, _hotPlugHandle[1]); - - if (_libUSBDeviceThread) - { - if (_libUSBDeviceThread->joinable()) - { - (void)_libUSBDeviceThread->join(); - } - delete _libUSBDeviceThread; - _libUSBDeviceThread = nullptr; - } - - (void)libusb_exit(NULL); - LOGINFO("libUSBClose Successed"); -} - -void USBDeviceImplementation::libUSBEventsHandlingThread(void) -{ - int retValue = LIBUSB_SUCCESS; - - while (_handlingUSBDeviceEvents) - { - retValue = libusb_handle_events (NULL); - - if (LIBUSB_SUCCESS != retValue) - { - LOGERR ("libusb_handle_events() failed: %s\n", libusb_strerror((enum libusb_error)retValue)); - } - } -} - -int USBDeviceImplementation::libUSBHotPlugCallbackDeviceAttached(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) -{ - Exchange::IUSBDevice::USBDevice usbDevice = {0}; - - (void)ctx; - (void)event; - (void)user_data; - - ASSERT (nullptr != dev); - - if (nullptr != dev) - { - if (Core::ERROR_NONE == USBDeviceImplementation::instance()->getUSBDeviceStructFromDeviceDescriptor(dev, &usbDevice)) - { - JsonObject params, device; - - device["deviceclass"] = usbDevice.deviceClass; - device["devicesubclass"] = usbDevice.deviceSubclass; - device["devicename"] = usbDevice.deviceName; - device["devicepath"] = usbDevice.devicePath; - - params["device"] = device; - - LOGINFO ("usbDevice.deviceClass: %u usbDevice.deviceSubclass:%u usbDevice.deviceName:%s devicePath:%s", - usbDevice.deviceClass, - usbDevice.deviceSubclass, - usbDevice.deviceName.c_str(), - usbDevice.devicePath.c_str()); - - USBDeviceImplementation::instance()->dispatchEvent(USBDeviceImplementation::Event::USBDEVICE_HOTPLUG_EVENT_DEVICE_ARRIVED, usbDevice); - } - else - { - LOGERR ("getUSBDeviceStructFromDeviceDescriptor Failed"); - } - } - else - { - LOGERR ("libusb_device is null"); - } - - return 0; -} - -int USBDeviceImplementation::libUSBHotPlugCallbackDeviceDetached(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) -{ - Exchange::IUSBDevice::USBDevice usbDevice = {0}; - - (void)ctx; - (void)event; - (void)user_data; - - ASSERT (nullptr != dev); - - if (nullptr != dev) - { - if (Core::ERROR_NONE == USBDeviceImplementation::instance()->getUSBDeviceStructFromDeviceDescriptor(dev, &usbDevice)) - { - LOGINFO ("usbDevice.deviceClass: %u usbDevice.deviceSubclass:%u usbDevice.deviceName:%s devicePath:%s", - usbDevice.deviceClass, - usbDevice.deviceSubclass, - usbDevice.deviceName.c_str(), - usbDevice.devicePath.c_str()); - - USBDeviceImplementation::instance()->dispatchEvent(USBDeviceImplementation::Event::USBDEVICE_HOTPLUG_EVENT_DEVICE_LEFT, usbDevice); - } - else - { - LOGERR ("getUSBDeviceStructFromDeviceDescriptor Failed"); - } - } - else - { - LOGERR ("libusb_device is null"); - } - - return 0; -} - -void USBDeviceImplementation::getDeviceSerialNumber(libusb_device *pDev, string &serialNumber) -{ - uint8_t devPath[8] = {0}; - char path[256] = {0}; - string sysfsPath = ""; - int numbOfElements = 0; - uint8_t busNumber = 0; - int indexPath = 0; - - // Get bus number from libusb device - busNumber = libusb_get_bus_number(pDev); - - // Construct sysfs path - sysfsPath = std::to_string(busNumber) + "-"; - - numbOfElements = libusb_get_port_numbers(pDev, devPath, sizeof(devPath)); - - if (numbOfElements > 0) - { - sysfsPath += std::to_string(devPath[0]); - - for (indexPath = 1; indexPath < numbOfElements; indexPath++) - { - sysfsPath += "." + std::to_string(devPath[indexPath]); - } - } - - std::snprintf(path, sizeof(path), "%s/%s/serial", PLUGIN_USBDEVICE_PATH, sysfsPath.c_str()); - - string filePath = path; - - if (!filePath.empty()) - { - // Open the file using std::ifstream - std::ifstream file(filePath); - - if (!file.is_open()) - { - LOGERR("Error opening file: %s", filePath.c_str()); - } - else - { - // Read the file content into a string - std::getline(file, serialNumber); - if (serialNumber.empty()) - { - LOGERR("Error opening file: %s", filePath.c_str()); - } - // Close the file - file.close(); - } - } -} - -void USBDeviceImplementation::getDevicePathFromDevice(libusb_device *pDev, string &devPath, string& deviceSerialNumber) -{ - const string dirPath = string(PLUGIN_USBDEVICE_BLOCKPATH); - DIR* dir = nullptr; - bool pathFound = false; - - // Get the device serial number - getDeviceSerialNumber(pDev, deviceSerialNumber); - - if (deviceSerialNumber.empty()) - { - LOGERR(" Failed read Serail Number"); - } - else - { - dir = opendir(dirPath.c_str()); - - if (!dir) - { - LOGERR("Error opening directory: %s", dirPath.c_str()); - } - else - { - // Iterate through directory entries - struct dirent* blockDirEntry = nullptr; - - while ((false == pathFound) && (((blockDirEntry = readdir(dir)) != nullptr))) - { - if (string(blockDirEntry->d_name) != "." && string(blockDirEntry->d_name) != "..") - { - string deviceName(blockDirEntry->d_name); - - // Check if the directory name starts with 'sd' - if (deviceName.rfind("sd", 0) == 0) - { - // Construct the path to the vendor and model file - string vendorPath = dirPath + "/" + deviceName + "/" + PLUGIN_USBDEVICE_VENDOR_PATH; - string modelPath = dirPath + "/" + deviceName + "/" + PLUGIN_USBDEVICE_MODEL_PATH; - string vendorName; - string modelName; - string blockDeviceName; - - // Open the vendor file - std::ifstream vendorFile(vendorPath); - - if (!vendorFile.is_open()) - { - LOGERR("Error opening file: %s", vendorPath.c_str()); - continue; - } - - std::getline(vendorFile, vendorName); - if (vendorFile.fail()) - { - LOGERR("Error reading file: %s", vendorPath.c_str()); - vendorFile.close(); - continue; - } - - auto endString = vendorName.find_last_not_of(' '); - if (endString != std::string::npos) - { - vendorName.erase(endString + 1); - } - - vendorFile.close(); - - // Open the model file - std::ifstream modelFile(modelPath); - - if (!modelFile.is_open()) - { - LOGERR("Error opening file: %s", modelPath.c_str()); - continue; - } - - std::getline(modelFile, modelName); - if (modelFile.fail()) - { - LOGERR("Error reading file: %s", modelPath.c_str()); - modelFile.close(); - continue; - } - - modelFile.close(); - - std::replace(modelName.begin(), modelName.end(), ' ', '_'); - auto end = modelName.find_last_not_of('_'); - if (end != std::string::npos) - { - modelName.erase(end + 1); - } - - blockDeviceName = string("usb-") + vendorName + string("_") + modelName + string("_"); - - const string diskDirPath = string(PLUGIN_USBDEVICE_DEV_DISK_PATH); - DIR* diskDir = nullptr; - - diskDir = opendir(diskDirPath.c_str()); - - if (!diskDir) - { - LOGERR("Error opening directory: %s", diskDirPath.c_str()); - } - else - { - // Iterate through directory entries - struct dirent* diskDirEntry = nullptr; - - while ((diskDirEntry = readdir(diskDir)) != nullptr) - { - if (diskDirEntry->d_type == DT_LNK && string(diskDirEntry->d_name) != "." && string(diskDirEntry->d_name) != "..") - { - string usbDeviceName(diskDirEntry->d_name); - - // Check the directory name starts with blockDeviceName Ex: usb-Generic_Flash_Disk_ - if (usbDeviceName.rfind("usb", 0) == 0) - { - string symlinkFile = diskDirPath + usbDeviceName; - boost::filesystem::path symlink_path(symlinkFile); - - boost::filesystem::path target_path = boost::filesystem::read_symlink(symlink_path); - - if ((target_path.string().find(deviceName) != std::string::npos) && - (usbDeviceName.find(deviceSerialNumber) != std::string::npos)) - { - devPath = "/dev/" + deviceName; - pathFound = true; - break; - } - } - } - } - closedir(diskDir); - } - } - } - } - // Close the directory - closedir(dir); - } - } -} - -uint32_t USBDeviceImplementation::getUSBDescriptorValue(libusb_device_handle *handle, uint16_t languageID, int descriptorIndex, std::string &stringDescriptor) -{ - uint32_t status = Core::ERROR_GENERAL; - int retValue = LIBUSB_SUCCESS; - unsigned char descBuf[256]; - - // Check that descriptorIndex is valid - if (descriptorIndex > 0) - { - memset(descBuf, 0, sizeof(descBuf)); - retValue = libusb_get_string_descriptor(handle, descriptorIndex, languageID, descBuf, sizeof(descBuf)); - if (retValue < 0) - { - retValue = libusb_get_string_descriptor_ascii(handle, descriptorIndex, descBuf, sizeof(descBuf)); - if (retValue < 0) - { - LOGERR("libusb_get_string_descriptor_ascii failed: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - stringDescriptor = string(reinterpret_cast(descBuf)); - status = Core::ERROR_NONE; - } - LOGERR("languageID: %u, libusb_get_string_descriptor failed: %s", languageID, libusb_strerror((enum libusb_error)retValue)); - } - else if (descBuf[1] != LIBUSB_DT_STRING) - { - LOGERR("String descriptor not received"); - } - else if (descBuf[0] > static_cast(retValue)) - { - LOGERR("String descriptor not received correctly"); - } - else - { - size_t bufStrLen = descBuf[0]; - uint16_t descValue; - // Copy the string descriptor information - - for (size_t i = USB_STRING_DESC_HEADER_LENGTH; i < bufStrLen; i+=2) - { - descValue = (uint16_t)((uint16_t)(descBuf[i]) | (uint16_t)((uint16_t)(descBuf[i + 1]) << 8)); - if (descValue < 0x80) - { - stringDescriptor += static_cast(descValue); - } - else - { - stringDescriptor += static_cast(descValue); - } - } - LOGINFO("stringDescriptor: %s, size:%d",stringDescriptor.c_str(),bufStrLen); - status = Core::ERROR_NONE; - } - } - else - { - LOGERR("Invalid descriptorIndex"); - } - return status; -} - -uint32_t USBDeviceImplementation::getUSBExtInfoStructFromDeviceDescriptor(libusb_device *pDev, - struct libusb_device_descriptor *pDesc, - Exchange::IUSBDevice::USBDeviceInfo *pUSBDeviceInfo) -{ - uint32_t status = Core::ERROR_GENERAL; - int retValue = LIBUSB_SUCCESS; - libusb_device_handle *devHandle = nullptr; - uint8_t langBuff[256] = {0}; - - ASSERT (nullptr != pDesc); - ASSERT (nullptr != pDev); - ASSERT (nullptr != pUSBDeviceInfo); - - if ((nullptr == pDev) || (nullptr == pDesc) || (nullptr == pUSBDeviceInfo)) - { - LOGERR ("pDev or pDesc or p_numLanguageIds is nullptr"); - } - else if ((retValue = libusb_open(pDev, &devHandle)) != LIBUSB_SUCCESS) - { - LOGERR ("Error libusb_open: %s", libusb_strerror((enum libusb_error)retValue)); - } - else if (4 < (retValue = libusb_get_string_descriptor(devHandle, 0, 0, (unsigned char*)langBuff, sizeof(langBuff)))) - { - LOGINFO("SerialNumber:%d,Manufacturer:%d,Product:%d", pDesc->iSerialNumber,pDesc->iManufacturer,pDesc->iProduct); - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, 0, pDesc->iManufacturer, pUSBDeviceInfo->productInfo1.manufacturer))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, 0, pDesc->iProduct, pUSBDeviceInfo->productInfo1.product))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, 0, pDesc->iSerialNumber, pUSBDeviceInfo->productInfo1.serialNumber))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - LOGERR ("Error libusb_get_string_descriptor: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - int devIndex = 2; - - pUSBDeviceInfo->numLanguageIds = (langBuff[0] - 2) / 2; - - LOGINFO("numLanguageIDs = %d", pUSBDeviceInfo->numLanguageIds); - - for (int languageCount = 0; languageCount< pUSBDeviceInfo->numLanguageIds; ++languageCount) - { - if (0 == languageCount) - { - pUSBDeviceInfo->productInfo1.languageId = (uint16_t)((uint16_t)(langBuff[devIndex]) | (uint16_t)((uint16_t)(langBuff[devIndex + 1]) << 8)); - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo1.languageId, pDesc->iSerialNumber, pUSBDeviceInfo->productInfo1.serialNumber))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo1.languageId, pDesc->iManufacturer, pUSBDeviceInfo->productInfo1.manufacturer))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo1.languageId, pDesc->iProduct, pUSBDeviceInfo->productInfo1.product))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - } - else if (1 == languageCount) - { - pUSBDeviceInfo->productInfo2.languageId = (uint16_t)((uint16_t)(langBuff[devIndex]) | (uint16_t)((uint16_t)(langBuff[devIndex + 1]) << 8)); - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo2.languageId, pDesc->iSerialNumber, pUSBDeviceInfo->productInfo2.serialNumber))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo2.languageId, pDesc->iManufacturer, pUSBDeviceInfo->productInfo2.manufacturer))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo2.languageId, pDesc->iProduct, pUSBDeviceInfo->productInfo2.product))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - } - else if (2 == languageCount) - { - pUSBDeviceInfo->productInfo3.languageId = (uint16_t)((uint16_t)(langBuff[devIndex]) | (uint16_t)((uint16_t)(langBuff[devIndex + 1]) << 8)); - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo3.languageId, pDesc->iSerialNumber, pUSBDeviceInfo->productInfo3.serialNumber))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo3.languageId, pDesc->iManufacturer, pUSBDeviceInfo->productInfo3.manufacturer))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo3.languageId, pDesc->iProduct, pUSBDeviceInfo->productInfo3.product))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - } - else if (3 == languageCount) - { - pUSBDeviceInfo->productInfo4.languageId = (uint16_t)((uint16_t)(langBuff[devIndex]) | (uint16_t)((uint16_t)(langBuff[devIndex + 1]) << 8)); - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo4.languageId, pDesc->iSerialNumber, pUSBDeviceInfo->productInfo4.serialNumber))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo4.languageId, pDesc->iManufacturer, pUSBDeviceInfo->productInfo4.manufacturer))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - - if (Core::ERROR_NONE != (status = getUSBDescriptorValue(devHandle, pUSBDeviceInfo->productInfo4.languageId, pDesc->iProduct, pUSBDeviceInfo->productInfo4.product))) - { - LOGERR ("Error getUSBDescriptorValue: %s", libusb_strerror((enum libusb_error)retValue)); - } - } - else - { - LOGWARN ("Maximum four prdouct info only supported"); - } - devIndex += 2; // Move to the next language ID - } - status = Core::ERROR_NONE; - } - - if (devHandle) - { - libusb_close(devHandle); - } - - return status; -} - -uint32_t USBDeviceImplementation::getUSBDeviceInfoStructFromDeviceDescriptor(libusb_device *pDev, Exchange::IUSBDevice::USBDeviceInfo *pUSBDeviceInfo) -{ - struct libusb_device_descriptor desc = {0}; - libusb_config_descriptor *config_desc; - char deviceName[16] = {0}; - uint32_t status = Core::ERROR_GENERAL; - int retValue = LIBUSB_SUCCESS; - - ASSERT (nullptr != pDev); - ASSERT (nullptr != pUSBDeviceInfo); - - if ((nullptr != pDev) && (nullptr != pUSBDeviceInfo)) - { - if (LIBUSB_SUCCESS != (retValue = libusb_get_device_descriptor(pDev, &desc))) - { - LOGERR("Error getting device descriptor: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - pUSBDeviceInfo->vendorId = desc.idVendor; - pUSBDeviceInfo->productId = desc.idProduct; - - - - sprintf(deviceName, "%03d/%03d", libusb_get_bus_number(pDev), libusb_get_device_address(pDev)); - pUSBDeviceInfo->device.deviceName = std::string(deviceName); - - if (LIBUSB_CLASS_PER_INTERFACE == desc.bDeviceClass) - { - getUSBDevicClassFromInterfaceDescriptor(pDev, pUSBDeviceInfo->device.deviceClass, pUSBDeviceInfo->device.deviceSubclass); - } - - if (LIBUSB_CLASS_MASS_STORAGE != pUSBDeviceInfo->device.deviceClass) - { - pUSBDeviceInfo->device.deviceClass = desc.bDeviceClass; - pUSBDeviceInfo->device.deviceSubclass = desc.bDeviceSubClass; - } - else - { - string serialNumber; - - /* Getting the device path and device serialNumber */ - getDevicePathFromDevice(pDev, pUSBDeviceInfo->device.devicePath, pUSBDeviceInfo->serialNumber); - } - - /* Need to check how to get flag */ - pUSBDeviceInfo->flags = DEVICE_FLAGS_DRIVER_AVAILABLE; - pUSBDeviceInfo->portNumber = libusb_get_port_number(pDev); - pUSBDeviceInfo->protocol = desc.bDeviceProtocol; - pUSBDeviceInfo->busSpeed = (Exchange::IUSBDevice::USBDeviceSpeed)libusb_get_device_speed(pDev); - - if (LIBUSB_SUCCESS == (retValue = libusb_get_active_config_descriptor ( pDev, &config_desc ))) - { - if (config_desc->bmAttributes & LIBUSB_CONFIG_ATT_SELF_POWERED ) - { - pUSBDeviceInfo->deviceStatus = WPEFramework::Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_SELF_POWERED | \ - WPEFramework::Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE; - } - else - { - pUSBDeviceInfo->deviceStatus = WPEFramework::Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_ACTIVE; - } - LOGINFO("bmAttributes: %u",config_desc->bmAttributes); - } - else - { - pUSBDeviceInfo->deviceStatus = WPEFramework::Exchange::IUSBDevice::USBDeviceStatus::DEVICE_STATUS_NO_DEVICE_CONNECTED; - LOGERR("Error libusb_get_active_config_descriptor: %s", libusb_strerror((enum libusb_error)retValue)); - } - if (Core::ERROR_NONE != (status = getUSBExtInfoStructFromDeviceDescriptor(pDev, &desc, pUSBDeviceInfo))) - { - LOGERR("Error getUSBExtInfoStructFromDeviceDescriptor"); - } - else - { - status = Core::ERROR_NONE; - } - } - } - else - { - LOGERR("pDev or pUSBDeviceInfo is nullptr"); - } - - - - - - - - - - - - - - - - return status; -} - -void USBDeviceImplementation::getUSBDevicClassFromInterfaceDescriptor(libusb_device *pDev, uint8_t &bDeviceClass, uint8_t &bDeviceSubClass) -{ - // Get configuration descriptor - libusb_config_descriptor *config = nullptr; - if (libusb_get_config_descriptor(pDev, 0, &config) == LIBUSB_SUCCESS) - { - if (config) - { - // Iterate over interfaces - for (int j = 0; j < config->bNumInterfaces; j++) - { - const libusb_interface *interface = &config->interface[j]; - for (int k = 0; k < interface->num_altsetting; k++) - { - const libusb_interface_descriptor *interface_desc = &interface->altsetting[k]; - - // Check if the interface class is Mass Storage - if (LIBUSB_CLASS_MASS_STORAGE == interface_desc->bInterfaceClass) - { - LOGINFO("Interface %d is a mass storage interface", j); - bDeviceClass = interface_desc->bInterfaceClass; - bDeviceSubClass = interface_desc->bInterfaceSubClass; - } - } - } - libusb_free_config_descriptor(config); - } - } -} - -uint32_t USBDeviceImplementation::getUSBDeviceStructFromDeviceDescriptor(libusb_device *pDev, Exchange::IUSBDevice::USBDevice *pusbDevice) -{ - struct libusb_device_descriptor desc = {0}; - uint32_t status = Core::ERROR_GENERAL; - int retValue = LIBUSB_SUCCESS; - - ASSERT (nullptr != pDev); - ASSERT (nullptr != pusbDevice); - - if ((nullptr != pDev) && (nullptr != pusbDevice)) - { - retValue = libusb_get_device_descriptor(pDev, &desc); - - if (LIBUSB_SUCCESS == retValue) - { - pusbDevice->deviceName = (boost::format("%03d/%03d") % (int)libusb_get_bus_number(pDev) % (int)libusb_get_device_address(pDev)).str(); - - if (LIBUSB_CLASS_PER_INTERFACE == desc.bDeviceClass) - { - getUSBDevicClassFromInterfaceDescriptor(pDev, pusbDevice->deviceClass, pusbDevice->deviceSubclass); - } - else - { - pusbDevice->deviceClass = desc.bDeviceClass; - pusbDevice->deviceSubclass = desc.bDeviceSubClass; - } - - if (LIBUSB_CLASS_MASS_STORAGE == pusbDevice->deviceClass) - { - string serialNumber; - int retryCount = 2; - - while( retryCount ) - { - /* Getting the device path */ - getDevicePathFromDevice(pDev, pusbDevice->devicePath, serialNumber); - - if(pusbDevice->devicePath.empty()) - { - LOGWARN ("device Path not found retrying it"); - --retryCount; - sleep(2); - } - else - { - break; - } - } - } - - status = Core::ERROR_NONE; - } - else - { - LOGERR ("Error getting device descriptor: %s",libusb_strerror((enum libusb_error)retValue)); - } - } - - return status; -} - -/** - * Register a notification callback - */ -Core::hresult USBDeviceImplementation::Register(Exchange::IUSBDevice::INotification *notification) -{ - ASSERT (nullptr != notification); - - _adminLock.Lock(); - - // Make sure we can't register the same notification callback multiple times - if (std::find(_usbDeviceNotification.begin(), _usbDeviceNotification.end(), notification) == _usbDeviceNotification.end()) - { - LOGINFO("Register notification"); - _usbDeviceNotification.push_back(notification); - notification->AddRef(); - } - - _adminLock.Unlock(); - - return Core::ERROR_NONE; -} - -/** - * Unregister a notification callback - */ -Core::hresult USBDeviceImplementation::Unregister(Exchange::IUSBDevice::INotification *notification ) -{ - uint32_t status = Core::ERROR_GENERAL; - - ASSERT (nullptr != notification); - - _adminLock.Lock(); - - // Make sure we can't unregister the same notification callback multiple times - auto itr = std::find(_usbDeviceNotification.begin(), _usbDeviceNotification.end(), notification); - if (itr != _usbDeviceNotification.end()) - { - (*itr)->Release(); - LOGINFO("Unregister notification"); - _usbDeviceNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - - _adminLock.Unlock(); - - return status; -} - -void USBDeviceImplementation::dispatchEvent(Event event, Exchange::IUSBDevice::USBDevice usbDevice) -{ - Core::IWorkerPool::Instance().Submit(Job::Create(this, event, usbDevice)); -} - -void USBDeviceImplementation::Dispatch(Event event, const Exchange::IUSBDevice::USBDevice usbDevice) -{ - _adminLock.Lock(); - - std::list::const_iterator index(_usbDeviceNotification.begin()); - - switch(event) { - case USBDEVICE_HOTPLUG_EVENT_DEVICE_ARRIVED: - LOGINFO("USBDEVICE_HOTPLUG_EVENT_DEVICE_ARRIVED Received"); - while (index != _usbDeviceNotification.end()) - { - LOGINFO("Call OnDevicePluggedIn"); - - (*index)->OnDevicePluggedIn(usbDevice); - ++index; - } - break; - - case USBDEVICE_HOTPLUG_EVENT_DEVICE_LEFT: - LOGINFO("USBDEVICE_HOTPLUG_EVENT_DEVICE_LEFT Received"); - while (index != _usbDeviceNotification.end()) - { - LOGINFO("Call OnDevicePluggedOut"); - (*index)->OnDevicePluggedOut(usbDevice); - ++index; - } - break; - - default: - break; - } - - _adminLock.Unlock(); -} - -Core::hresult USBDeviceImplementation::GetDeviceList(IUSBDeviceIterator*& devices) const -{ - uint32_t status = Core::ERROR_GENERAL; - std::list usbDeviceList; - libusb_device **devs = nullptr; - ssize_t devCount = 0; - - _adminLock.Lock(); - - LOGINFO("GetDeviceList"); - - devCount = libusb_get_device_list(NULL, &devs); - - LOGINFO("devCount:%zd", devCount); - - if (devCount > 0) - { - for (int index = 0; index < devCount; index++) - { - Exchange::IUSBDevice::USBDevice usbDevice = {0}; - - status = USBDeviceImplementation::instance()->getUSBDeviceStructFromDeviceDescriptor(devs[index], &usbDevice); - - if (Core::ERROR_NONE == status) - { - LOGINFO ("usbDevice.deviceClass: %u usbDevice.deviceSubclass:%u usbDevice.deviceName:%s devicePath:%s", - usbDevice.deviceClass, - usbDevice.deviceSubclass, - usbDevice.deviceName.c_str(), - usbDevice.devicePath.c_str()); - - usbDeviceList.emplace_back(usbDevice); - } - else - { - LOGWARN ("getUSBDeviceStructFromDeviceDescriptor Failed"); - } - } - - libusb_free_device_list(devs, 1); - if (Core::ERROR_NONE == status) - { - devices = (Core::Service>::Create(usbDeviceList)); - } - } - else - { - LOGWARN("USBDevice Not found"); - status = Core::ERROR_NONE; - } - _adminLock.Unlock(); - - return status; -} - -Core::hresult USBDeviceImplementation::GetDeviceInfo(const string &deviceName, USBDeviceInfo& deviceInfo) const -{ - uint32_t status = Core::ERROR_GENERAL; - libusb_device **devs = nullptr; - ssize_t devCount = 0; - - _adminLock.Lock(); - - LOGINFO("GetDeviceInfo"); - - devCount = libusb_get_device_list(NULL, &devs); - - LOGINFO("devCount:%zd", devCount); - - if (devCount > 0) - { - for (int index = 0; index < devCount; index++) - { - char usbDeviceName[10] = {0}; - - (void)sprintf(usbDeviceName, "%03d/%03d", libusb_get_bus_number(devs[index]), libusb_get_device_address(devs[index])); - - if (deviceName.compare(string(usbDeviceName)) != 0) - { - continue; - } - else - { - uint8_t portPath[8] = {0}; // Maximum 8 levels (depends on USB architecture) - - status = USBDeviceImplementation::instance()->getUSBDeviceInfoStructFromDeviceDescriptor(devs[index], &deviceInfo); - if (Core::ERROR_NONE != status) - { - deviceInfo.deviceLevel = libusb_get_port_numbers(devs[index], portPath, sizeof(portPath)); - if ( 1 < deviceInfo.deviceLevel ) - { - for (ssize_t j = 0; j < devCount; j++) - { - libusb_device *device = devs[j]; - uint8_t portNo = libusb_get_port_number(device); - if (portPath[deviceInfo.deviceLevel - 2] == portNo) - { - deviceInfo.parentId = j; - } - } - } - else - { - deviceInfo.parentId = 0; - } - } - else - { - LOGWARN ("getUSBDeviceInfoStructFromDeviceDescriptor Failed"); - } - } - } - libusb_free_device_list(devs, 1); - } - else - { - LOGWARN("USBDevice Not found"); - } - _adminLock.Unlock(); - - return status; -} - -Core::hresult USBDeviceImplementation::BindDriver(const string &deviceName) const -{ - uint32_t status = Core::ERROR_GENERAL; - libusb_device **devs = nullptr; - ssize_t devCount = 0; - int retValue = LIBUSB_SUCCESS; - libusb_device_handle *devHandle = nullptr; - - _adminLock.Lock(); - - LOGINFO("BindDriver"); - - devCount = libusb_get_device_list(NULL, &devs); - - LOGINFO("devCount:%zd", devCount); - - if (devCount > 0) - { - for (int index = 0; index < devCount; index++) - { - char usbDeviceName[10] = {0}; - - (void)sprintf(usbDeviceName, "%03d/%03d", libusb_get_bus_number(devs[index]), libusb_get_device_address(devs[index])); - - if (deviceName.compare(string(usbDeviceName)) != 0) - { - continue; /*Not matched continue to check next dev struct */ - } - else - { - if (nullptr == devs[index]) - { - LOGERR ("devs is nullptr"); - } - else if ((retValue = libusb_open(devs[index], &devHandle)) != LIBUSB_SUCCESS) - { - LOGERR ("Error libusb_open: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - int kernelDriverStatus = libusb_kernel_driver_active(devHandle, 0); - - if (kernelDriverStatus < 0) - { - LOGERR("Error libusb_kernel_driver_active: %s", libusb_strerror((enum libusb_error)kernelDriverStatus)); - } - else if (kernelDriverStatus == 0) - { - // No driver is active, so attach it - if ((retValue = libusb_attach_kernel_driver(devHandle, 0)) != LIBUSB_SUCCESS) - { - LOGERR("Error libusb_attach_kernel_driver: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - status = Core::ERROR_NONE; - LOGINFO("BindDriver succeeded"); - } - } - else // kernelDriverStatus == 1 - { - LOGINFO("libusb kernel driver is already active"); - status = Core::ERROR_NONE; - LOGINFO("BindDriver succeeded"); - } - - // Always close the device handle - libusb_close(devHandle); - devHandle = nullptr; - } - break; - } - } - - libusb_free_device_list(devs, 1); - } - else - { - LOGWARN("USBDevice Not found"); - } - _adminLock.Unlock(); - - return status; -} - -Core::hresult USBDeviceImplementation::UnbindDriver(const string &deviceName) const -{ - uint32_t status = Core::ERROR_GENERAL; - libusb_device **devs = nullptr; - ssize_t devCount = 0; - int retValue = LIBUSB_SUCCESS; - libusb_device_handle *devHandle = nullptr; - - _adminLock.Lock(); - - LOGINFO("UnbindDriver"); - - devCount = libusb_get_device_list(NULL, &devs); - - LOGINFO("devCount:%zd", devCount); - - if (devCount > 0) - { - for (int index = 0; index < devCount; index++) - { - char usbDeviceName[10] = {0}; - - (void)sprintf(usbDeviceName, "%03d/%03d", libusb_get_bus_number(devs[index]), libusb_get_device_address(devs[index])); - - if (deviceName.compare(string(usbDeviceName)) != 0) - { - continue; - } - else - { - if (nullptr == devs[index]) - { - LOGERR ("devs is nullptr"); - } - else if ((retValue = libusb_open(devs[index], &devHandle)) != LIBUSB_SUCCESS) - { - LOGERR ("Error libusb_open: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - int kernelDriverStatus = libusb_kernel_driver_active(devHandle, 0); - - if (kernelDriverStatus < 0) - { - LOGERR("Error libusb_kernel_driver_active: %s", libusb_strerror((enum libusb_error)kernelDriverStatus)); - } - else if (kernelDriverStatus == 0) - { - // No driver is active - status = Core::ERROR_NONE; - LOGINFO("No kernel driver is active"); - } - else // kernelDriverStatus == 1 - { - // A driver is active, try to detach it - if ((retValue = libusb_detach_kernel_driver(devHandle, 0)) != LIBUSB_SUCCESS) - { - LOGERR("Error libusb_detach_kernel_driver: %s", libusb_strerror((enum libusb_error)retValue)); - } - else - { - status = Core::ERROR_NONE; - LOGINFO("Kernel driver successfully detached"); - } - } - - // Always close the device handle - libusb_close(devHandle); - devHandle = nullptr; - } - break; - } - } - - libusb_free_device_list(devs, 1); - } - else - { - LOGWARN("USBDevice Not found"); - } - _adminLock.Unlock(); - - return status; -} -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBDevice/USBDeviceImplementation.h b/USBDevice/USBDeviceImplementation.h deleted file mode 100755 index c812cde..0000000 --- a/USBDevice/USBDeviceImplementation.h +++ /dev/null @@ -1,167 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include "tracing/Logging.h" -#include -#include -#include -#include -#include -#include -#include "libusb.h" - -/** -* @brief Bit in the port status to check if device is connected or not -*/ -#define STATUS_BIT_PORT_CONNECTION 0x0001 - -/** -* @brief Bit in the port status to check if port is enabled or not -*/ -#define STATUS_BIT_PORT_ENABLED 0x0002 - -/** -* @brief Bit in the port status to check if device connected to the port is suspended or not -*/ -#define STATUS_BIT_PORT_DEVICE_SUSPENDED 0x0004 - -/** -* @brief Bit in the port status to check if there is over current in the port -*/ -#define STATUS_BIT_PORT_OVER_CURRENT 0x0008 - -/** -* @brief Bit in the device status to check if the device is self powered or bus powered -*/ -#define STATUS_BIT_DEVICE_SELF_POWERED 0x01 - -/* -* Configuration characteristics -* D7: Reserved (set to one) -* D6: Self-powered // If the D6 not set, the device is bus powered -* D5: Remote Wakeup -* D4...0: Reserved (reset to zero) -* D7 is reserved and must be set to one for historical reasons. -*/ -#define LIBUSB_CONFIG_ATT_SELF_POWERED 0x40 -namespace WPEFramework { -namespace Plugin { - class USBDeviceImplementation : public Exchange::IUSBDevice{ - public: - // We do not allow this plugin to be copied !! - USBDeviceImplementation(); - ~USBDeviceImplementation() override; - - static USBDeviceImplementation* instance(USBDeviceImplementation *USBDeviceImpl = nullptr); - - // We do not allow this plugin to be copied !! - USBDeviceImplementation(const USBDeviceImplementation&) = delete; - USBDeviceImplementation& operator=(const USBDeviceImplementation&) = delete; - - BEGIN_INTERFACE_MAP(USBDeviceImplementation) - INTERFACE_ENTRY(Exchange::IUSBDevice) - END_INTERFACE_MAP - - public: - enum Event { - USBDEVICE_HOTPLUG_EVENT_DEVICE_ARRIVED, - USBDEVICE_HOTPLUG_EVENT_DEVICE_LEFT - }; - - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(USBDeviceImplementation *usbDeviceImplementation, Event event, Exchange::IUSBDevice::USBDevice &usbDevice) - : _usbDeviceImplementation(usbDeviceImplementation) - , _event(event) - , _usbDevice(usbDevice) { - if (_usbDeviceImplementation != nullptr) { - _usbDeviceImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (_usbDeviceImplementation != nullptr) { - _usbDeviceImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(USBDeviceImplementation *usbDeviceImplementation, Event event, Exchange::IUSBDevice::USBDevice usbDevice) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(usbDeviceImplementation, event, usbDevice))); -#else - return (Core::ProxyType(Core::ProxyType::Create(usbDeviceImplementation, event, usbDevice))); -#endif - } - - virtual void Dispatch() { - _usbDeviceImplementation->Dispatch(_event, _usbDevice); - } - private: - USBDeviceImplementation *_usbDeviceImplementation; - const Event _event; - const Exchange::IUSBDevice::USBDevice _usbDevice; - }; - - public: - virtual Core::hresult Register(Exchange::IUSBDevice::INotification *notification ) override ; - virtual Core::hresult Unregister(Exchange::IUSBDevice::INotification *notification ) override ; - Core::hresult GetDeviceList(IUSBDeviceIterator*& devices) const override; - Core::hresult GetDeviceInfo(const string &deviceName, USBDeviceInfo& deviceInfo) const override; - Core::hresult BindDriver(const string &deviceName) const override; - Core::hresult UnbindDriver(const string &deviceName) const override; - - private: - void dispatchEvent(Event, const Exchange::IUSBDevice::USBDevice usbDevice); - void Dispatch(Event event, const Exchange::IUSBDevice::USBDevice usbDevice); - uint32_t libUSBInit(void); - void libUSBClose(void); - void getUSBDevicClassFromInterfaceDescriptor(libusb_device *pDev, uint8_t &bDeviceClass, uint8_t &bDeviceSubClass); - void getDevicePathFromDevice(libusb_device *pDev, string &devPath, string& deviceSerialNumber); - void getDeviceSerialNumber(libusb_device *pDev, string &serialNumber); - uint32_t getUSBDescriptorValue(libusb_device_handle *handle, uint16_t languageID, int descriptorIndex, std::string &stringDescriptor); - uint32_t getUSBExtInfoStructFromDeviceDescriptor(libusb_device *pDev, - struct libusb_device_descriptor *pDesc, - Exchange::IUSBDevice::USBDeviceInfo *pUSBDeviceInfo); - uint32_t getUSBDeviceInfoStructFromDeviceDescriptor(libusb_device *pDev, Exchange::IUSBDevice::USBDeviceInfo *pUSBDeviceInfo); - uint32_t getUSBDeviceStructFromDeviceDescriptor(libusb_device *pDev, Exchange::IUSBDevice::USBDevice *pusbDevice); - static int libUSBHotPlugCallbackDeviceAttached(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data); - static int libUSBHotPlugCallbackDeviceDetached(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data); - void libUSBEventsHandlingThread(void); - - private: - mutable Core::CriticalSection _adminLock; - std::thread *_libUSBDeviceThread; - std::list _usbDeviceNotification; - bool _handlingUSBDeviceEvents; - libusb_hotplug_callback_handle _hotPlugHandle[2]; - - friend class Job; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBMassStorage/CHANGELOG.md b/USBMassStorage/CHANGELOG.md deleted file mode 100755 index 9566ca0..0000000 --- a/USBMassStorage/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/USBMassStorage/CMakeLists.txt b/USBMassStorage/CMakeLists.txt deleted file mode 100755 index a488d6f..0000000 --- a/USBMassStorage/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME USBMassStorage) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) -set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) - -set(PLUGIN_USB_MASS_STORAGE_AUTOSTART "false" CACHE STRING "Automatically start USBMassStorage plugin") -set(PLUGIN_USB_MASS_STORAGE_STARTUPORDER "45" CACHE STRING "To configure startup order of USBMassStorage plugin") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -if (NOT RDK_SERVICE_L2_TEST AND NOT RDK_SERVICES_L1_TEST) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBUSB REQUIRED libusb-1.0) -endif() - -add_library(${MODULE_NAME} SHARED - USBMassStorage.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -add_library(${PLUGIN_IMPLEMENTATION} SHARED - USBMassStorageImplementation.cpp - Module.cpp) - -include_directories(../helpers) - -if (NOT RDK_SERVICE_L2_TEST) - include_directories(${LIBUSB_INCLUDE_DIRS}) -endif() - -set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -if (RDK_SERVICE_L2_TEST) - find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) - if (TESTMOCKLIB_LIBRARIES) - message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,open -Wl,--wrap,mkdir -Wl,--wrap,mount -Wl,--wrap,umount -Wl,--wrap,ioctl -Wl,--wrap,statvfs -Wl,--wrap,statfs -Wl,--wrap,stat -Wl,--wrap,rmdir) - else (TESTMOCKLIB_LIBRARIES) - message ("Require ${TESTMOCKLIB_LIBRARIES} library") - endif (TESTMOCKLIB_LIBRARIES) -endif (RDK_SERVICES_L2_TEST) - -if (RDK_SERVICES_L1_TEST) - target_link_options(${PLUGIN_IMPLEMENTATION} PRIVATE -Wl,--wrap,open -Wl,--wrap,mkdir -Wl,--wrap,mount -Wl,--wrap,umount -Wl,--wrap,ioctl -Wl,--wrap,statvfs -Wl,--wrap,statfs -Wl,--wrap,stat -Wl,--wrap,rmdir) -endif (RDK_SERVICES_L1_TEST) -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -install(TARGETS ${PLUGIN_IMPLEMENTATION} - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) - diff --git a/USBMassStorage/Module.cpp b/USBMassStorage/Module.cpp deleted file mode 100755 index 713d4b1..0000000 --- a/USBMassStorage/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/USBMassStorage/Module.h b/USBMassStorage/Module.h deleted file mode 100755 index ecb9282..0000000 --- a/USBMassStorage/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_USBMassStorage -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/USBMassStorage/USBMassStorage.conf.in b/USBMassStorage/USBMassStorage.conf.in deleted file mode 100755 index 1fe6873..0000000 --- a/USBMassStorage/USBMassStorage.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -autostart = "@PLUGIN_USB_MASS_STORAGE_AUTOSTART@" -precondition = ["Platform"] -callsign = "org.rdk.UsbMassStorage" -startuporder = "@PLUGIN_USB_MASS_STORAGE_STARTUPORDER@" - -configuration = JSON() -rootobject = JSON() - -rootobject.add("mode", "@PLUGIN_USB_MASS_STORAGE_MODE@") -rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") -configuration.add("root", rootobject) - diff --git a/USBMassStorage/USBMassStorage.config b/USBMassStorage/USBMassStorage.config deleted file mode 100755 index 7a19b31..0000000 --- a/USBMassStorage/USBMassStorage.config +++ /dev/null @@ -1,15 +0,0 @@ -set(autostart ${PLUGIN_USB_MASS_STORAGE_AUTOSTART}) - -if(PLUGIN_USB_MASS_STORAGE_STARTUPORDER) -set (startuporder ${PLUGIN_USB_MASS_STORAGE_STARTUPORDER}) -endif() - -map() - key(root) - map() - kv(mode ${PLUGIN_USB_MASS_STORAGE_MODE}) - kv(locator lib${PLUGIN_IMPLEMENTATION}.so) - end() -end() -ans(configuration) - diff --git a/USBMassStorage/USBMassStorage.cpp b/USBMassStorage/USBMassStorage.cpp deleted file mode 100755 index bf3d909..0000000 --- a/USBMassStorage/USBMassStorage.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "USBMassStorage.h" -#include "UtilsLogging.h" -#include "UtilsJsonRpc.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 0 - -namespace WPEFramework -{ - - namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); - } - - namespace Plugin - { - - /* - *Register USBMassStorage module as wpeframework plugin - **/ - SERVICE_REGISTRATION(USBMassStorage, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - USBMassStorage::USBMassStorage() : PluginHost::JSONRPCErrorAssessor(USBMassStorage::OnJSONRPCError), - _service(nullptr), _connectionId(0), _usbMassStorage(nullptr), _usbStoragesNotification(this) - { - SYSLOG(Logging::Startup, (_T("USBMassStorage Constructor"))); - } - - USBMassStorage::~USBMassStorage() - { - SYSLOG(Logging::Shutdown, (string(_T("USBMassStorage Destructor")))); - } - - const string USBMassStorage::Initialize(PluginHost::IShell* service) - { - string message=""; - - ASSERT(nullptr != service); - ASSERT(nullptr == _service); - ASSERT(nullptr == _usbMassStorage); - ASSERT(0 == _connectionId); - - SYSLOG(Logging::Startup, (_T("USBMassStorage::Initialize: PID=%u"), getpid())); - - _service = service; - _service->AddRef(); - _service->Register(&_usbStoragesNotification); - _usbMassStorage = _service->Root(_connectionId, 5000, _T("USBMassStorageImplementation")); - - if(nullptr != _usbMassStorage) - { - configure = _usbMassStorage->QueryInterface(); - if (configure != nullptr) - { - uint32_t result = configure->Configure(_service); - if(result != Core::ERROR_NONE) - { - message = _T("UsbMassStorage could not be configured"); - } - } - else - { - message = _T("UsbMassStorage implementation did not provide a configuration interface"); - } - - // Register for notifications - _usbMassStorage->Register(&_usbStoragesNotification); - // Invoking Plugin API register to wpeframework - Exchange::JUSBMassStorage::Register(*this, _usbMassStorage); - } - else - { - SYSLOG(Logging::Startup, (_T("USBMassStorage::Initialize: Failed to initialise USBMassStorage plugin"))); - message = _T("USBMassStorage plugin could not be initialised"); - } - - if (0 != message.length()) - { - Deinitialize(service); - } - - return message; - } - - void USBMassStorage::Deinitialize(PluginHost::IShell* service) - { - ASSERT(_service == service); - - SYSLOG(Logging::Shutdown, (string(_T("USBMassStorage::Deinitialize")))); - - // Make sure the Activated and Deactivated are no longer called before we start cleaning up.. - _service->Unregister(&_usbStoragesNotification); - - if (nullptr != _usbMassStorage) - { - _usbMassStorage->Unregister(&_usbStoragesNotification); - Exchange::JUSBMassStorage::Unregister(*this); - - if (configure != nullptr) { - configure->Release(); - configure = nullptr; - } - - // Stop processing: - RPC::IRemoteConnection* connection = service->RemoteConnection(_connectionId); - VARIABLE_IS_NOT_USED uint32_t result = _usbMassStorage->Release(); - - _usbMassStorage = nullptr; - - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - - // If this was running in a (container) process... - if (nullptr != connection) - { - // Lets trigger the cleanup sequence for - // out-of-process code. Which will guard - // that unwilling processes, get shot if - // not stopped friendly :-) - try - { - connection->Terminate(); - // Log success if needed - LOGINFO("Connection terminated successfully."); - } - catch (const std::exception& e) - { - std::string errorMessage = "Failed to terminate connection: "; - errorMessage += e.what(); - LOGWARN("%s",errorMessage.c_str()); - } - - connection->Release(); - } - } - - _connectionId = 0; - _service->Release(); - _service = nullptr; - SYSLOG(Logging::Shutdown, (string(_T("USBMassStorage de-initialised")))); - } - - string USBMassStorage::Information() const - { - return ("The USBMassStorage Plugin manages device mounting and stores mount information."); - } - - void USBMassStorage::Deactivated(RPC::IRemoteConnection* connection) - { - if (connection->Id() == _connectionId) - { - LOGINFO("USBMassStorage Deactivated"); - ASSERT(nullptr != _service); - Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); - } - } - - void USBMassStorage::Notification::Activated(RPC::IRemoteConnection*) - { - } - - void USBMassStorage::Notification::Deactivated(RPC::IRemoteConnection *connection) - { - _parent.Deactivated(connection); - } - - void USBMassStorage::Notification::OnDeviceMounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) - { - Core::JSON::ArrayType mountPointsArray; - JsonData::USBMassStorage::USBStorageDeviceInfoData jsonDeviceInfo; - - if (mountPoints != nullptr) - { - Exchange::IUSBMassStorage::USBStorageMountInfo resultItem{}; - Core::JSON::String devicePath,deviceName; - - jsonDeviceInfo.DevicePath = deviceInfo.devicePath; - jsonDeviceInfo.DeviceName = deviceInfo.deviceName; - - while (mountPoints->Next(resultItem) == true) { mountPointsArray.Add() = resultItem; } - - Core::JSON::Container eventPayload; - eventPayload.Add(_T("deviceinfo"), &jsonDeviceInfo); - eventPayload.Add(_T("mountPoints"), &mountPointsArray); - - _parent.Notify(_T("onDeviceMounted"), eventPayload); - } - } - - void USBMassStorage::Notification::OnDeviceUnmounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) - { - Core::JSON::ArrayType mountPointsArray; - JsonData::USBMassStorage::USBStorageDeviceInfoData jsonDeviceInfo; - - if (mountPoints != nullptr) - { - Exchange::IUSBMassStorage::USBStorageMountInfo resultItem{}; - Core::JSON::String devicePath,deviceName; - - jsonDeviceInfo.DevicePath = deviceInfo.devicePath; - jsonDeviceInfo.DeviceName = deviceInfo.deviceName; - - while (mountPoints->Next(resultItem) == true) { mountPointsArray.Add() = resultItem; } - - Core::JSON::Container eventPayload; - eventPayload.Add(_T("deviceinfo"), &jsonDeviceInfo); - eventPayload.Add(_T("mountPoints"), &mountPointsArray); - - _parent.Notify(_T("onDeviceUnmounted"), eventPayload); - } - } - uint32_t USBMassStorage::OnJSONRPCError(const Core::JSONRPC::Context&, const string& method, const string& parameters, const uint32_t errorcode, string& errormessage) { - if(IS_ENTSERVICES_ERRORCODE(errorcode)) - errormessage = ERROR_MESSAGE(errorcode); - return errorcode; - } -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBMassStorage/USBMassStorage.h b/USBMassStorage/USBMassStorage.h deleted file mode 100755 index f907c3e..0000000 --- a/USBMassStorage/USBMassStorage.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include -#include - -#include "tracing/Logging.h" -#include - -namespace WPEFramework { -namespace Plugin { - - class USBMassStorage: public PluginHost::IPlugin, public PluginHost::JSONRPCErrorAssessor - { - private: - class Notification : public RPC::IRemoteConnection::INotification, - public Exchange::IUSBMassStorage::INotification - { - private: - Notification() = delete; - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; - - public: - explicit Notification(USBMassStorage* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - virtual ~Notification() - { - } - - BEGIN_INTERFACE_MAP(Notification) - INTERFACE_ENTRY(Exchange::IUSBMassStorage::INotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - - void Activated(RPC::IRemoteConnection*) override; - void Deactivated(RPC::IRemoteConnection *connection) override; - void OnDeviceMounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) override; - void OnDeviceUnmounted(const Exchange::IUSBMassStorage::USBStorageDeviceInfo &deviceInfo, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* const mountPoints) override; - - private: - USBMassStorage& _parent; - }; - - public: - // We do not allow this plugin to be copied !! - USBMassStorage(const USBMassStorage&) = delete; - USBMassStorage& operator=(const USBMassStorage&) = delete; - - USBMassStorage(); - virtual ~USBMassStorage(); - - BEGIN_INTERFACE_MAP(USBMassStorage) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IUSBMassStorage, _usbMassStorage) - END_INTERFACE_MAP - - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - static uint32_t OnJSONRPCError(const Core::JSONRPC::Context& context, const string& method, const string& parameters, const uint32_t errorcode, string& errormessage); - - private: - void Deactivated(RPC::IRemoteConnection* connection); - - private: - PluginHost::IShell* _service{}; - uint32_t _connectionId{}; - Exchange::IUSBMassStorage* _usbMassStorage{}; - Core::Sink _usbStoragesNotification; - Exchange::IConfiguration* configure{nullptr}; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/USBMassStorage/USBMassStorageImplementation.cpp b/USBMassStorage/USBMassStorageImplementation.cpp deleted file mode 100755 index c1909cc..0000000 --- a/USBMassStorage/USBMassStorageImplementation.cpp +++ /dev/null @@ -1,730 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "USBMassStorageImplementation.h" -#include "UtilsLogging.h" - -#define MEDIA_PATH "/tmp/media" -#define MOUNT_PATH "/tmp/media/usb" -#define FILE_SYSTEM_VFAT "vfat" -#define FILE_SYSTEM_EXFAT "exfat" - -using namespace std; - -namespace WPEFramework { -namespace Plugin { - - SERVICE_REGISTRATION(USBMassStorageImplementation, 1, 0); - USBMassStorageImplementation* USBMassStorageImplementation::_instance = nullptr; - USBMassStorageImplementation::USBMassStorageImplementation() - : _adminLock() - , _remoteUSBDeviceObject(nullptr) - , _USB_DeviceNotification(*this) - , _registeredEventHandlers(false) - , _service(nullptr) - { - LOGINFO("Create USBMassStorageImplementation Instance"); - USBMassStorageImplementation::_instance = this; - } - - uint32_t USBMassStorageImplementation::Configure(PluginHost::IShell* service) - { - uint32_t result = Core::ERROR_GENERAL; - if (service != nullptr) - { - _service = service; - _service->AddRef(); - result = Core::ERROR_NONE; - _remoteUSBDeviceObject = _service->QueryInterfaceByCallsign("org.rdk.UsbDevice"); - if (_remoteUSBDeviceObject != nullptr) - { - registerEventHandlers(); - - /* Getting USB Device list and mounting available USB devices */ - MountDevicesOnBootUp(); - } - else - { - LOGERR("_remoteUSBDeviceObject is null \n"); - } - } - else - { - LOGERR("service is null \n"); - } - - return result; - } - - USBMassStorageImplementation::~USBMassStorageImplementation() - { - if(_remoteUSBDeviceObject) - { - _remoteUSBDeviceObject->Release(); - _remoteUSBDeviceObject = nullptr; - } - _registeredEventHandlers = false; - - if (_service != nullptr) - { - _service->Release(); - _service = nullptr; - } - } - - void USBMassStorageImplementation::registerEventHandlers() - { - if(!_registeredEventHandlers && _remoteUSBDeviceObject) - { - _registeredEventHandlers = true; - _remoteUSBDeviceObject->Register(&_USB_DeviceNotification); - } - else - { - LOGERR("_remoteUSBDeviceObject is null \n"); - } - } - - Core::hresult USBMassStorageImplementation::Register(Exchange::IUSBMassStorage::INotification *notification) - { - _adminLock.Lock(); - if (nullptr != notification) - { - // Make sure we can't register the same notification callback multiple times - if (std::find(_usbStorageNotification.begin(), _usbStorageNotification.end(), notification) == _usbStorageNotification.end()) - { - _usbStorageNotification.push_back(notification); - notification->AddRef(); - } - else - { - LOGERR("same notification is registered already"); - } - } - _adminLock.Unlock(); - - return Core::ERROR_NONE; - } - - Core::hresult USBMassStorageImplementation::Unregister(Exchange::IUSBMassStorage::INotification *notification ) - { - uint32_t status = Core::ERROR_GENERAL; - - _adminLock.Lock(); - if (nullptr != notification) - { - // we just unregister one notification once - auto itr = std::find(_usbStorageNotification.begin(), _usbStorageNotification.end(), notification); - if (itr != _usbStorageNotification.end()) - { - (*itr)->Release(); - _usbStorageNotification.erase(itr); - status = Core::ERROR_NONE; - } - else - { - LOGERR("notification not found"); - } - } - _adminLock.Unlock(); - - return status; - } - - void USBMassStorageImplementation::Dispatch(Event event, USBStorageDeviceInfo storageDeviceInfo) - { - _adminLock.Lock(); - - switch(event) - { - case USB_STORAGE_EVENT_MOUNT: - DispatchMountEvent(storageDeviceInfo); - break; - case USB_STORAGE_EVENT_UNMOUNT: - DispatchUnMountEvent(storageDeviceInfo); - break; - default: - LOGERR("Unexpected event is received %u",event); - break; - } - - _adminLock.Unlock(); - } - - bool USBMassStorageImplementation::DeviceMount(const USBStorageDeviceInfo &storageDeviceInfo) - { - ifstream partitionsFile("/proc/partitions"); - std::vector partitions; - USBStorageMountFlags mountFlags = USBStorageMountFlags::READ_WRITE; - string line; - bool success = false; - size_t num_partitions = 0; - string prefix = "/dev/"; - string partitionPath; - - size_t pos = storageDeviceInfo.devicePath.find(prefix); - if (pos != std::string::npos) - { - partitionPath = storageDeviceInfo.devicePath.substr(pos + prefix.length()); - } - else - { - partitionPath = storageDeviceInfo.devicePath; - } - LOGINFO("partitionPath [%s]", partitionPath.c_str()); - - while (getline(partitionsFile, line)) - { - if (line.find(partitionPath) != std::string::npos && line != partitionPath) - { - string partition = "/dev/" + line.substr(line.find_last_of(' ') + 1); - LOGINFO("Device path [%s], partition [%s]", storageDeviceInfo.devicePath.c_str(),partition.c_str()); - partitions.push_back(partition); - } - } - num_partitions = partitions.size(); - LOGINFO("Device path[%s] Device Name[%s] num_partitions [%zd]",storageDeviceInfo.devicePath.c_str(),storageDeviceInfo.deviceName.c_str(),num_partitions-1); - - if (!directoryExists(MEDIA_PATH)) - { - if (mkdir(MEDIA_PATH, 0755) == -1) - { - LOGERR("Failed to create /tmp/media : %s",strerror(errno)); - } - } - - for (size_t i = 0; i < num_partitions; ++i) - { - string partition = partitions[i]; - string mountPoint; - Exchange::IUSBMassStorage::USBStorageMountInfo mountInfo = {}; - int index = 1; - - /* Skipping the mount path creation for partitions[0], as this is always device path(/dev/sdx). If there - is only one partition then we are creating the mount path on the device path (partitions[0]). */ - if((num_partitions > 1) && (i == 0)) - continue; - - while (directoryExists(MOUNT_PATH + std::to_string(index))) - { - ++index; - } - - mountPoint = MOUNT_PATH + std::to_string(index); - LOGINFO("MountPoint [%s]", mountPoint.c_str()); - if (mkdir(mountPoint.c_str(), 0755) == 0) - { - if ((mount(partition.c_str(), mountPoint.c_str(), FILE_SYSTEM_VFAT, 0, nullptr)) == 0) - { - mountInfo.fileSystem = VFAT; - LOGINFO("filetype is vfat"); - } - else if ((mount(partition.c_str(), mountPoint.c_str(), FILE_SYSTEM_EXFAT, 0, nullptr)) == 0) - { - LOGINFO("filetype is exfat"); - mountInfo.fileSystem = EXFAT; - } - else - { - LOGERR("Mount is failed for [%s]. Error[%s]", partition.c_str(), strerror(errno)); - if (rmdir(mountPoint.c_str()) != 0) - { - LOGERR("Directory[%s] removal is failed.", mountPoint.c_str()); - } - continue; - } - LOGINFO("[%s] is mounted successfully.",partition.c_str()); - mountInfo.partitionName = partition; - mountInfo.mountFlags = mountFlags; - mountInfo.mountPath = mountPoint; - - usbStorageMountInfo[storageDeviceInfo.deviceName].push_back(mountInfo); - success = true; - } - else - { - LOGERR("Failed to create folder[%s] to mount device. Error[%s]", mountPoint.c_str(), strerror(errno)); - } - } - return success; - } - - void USBMassStorageImplementation::DispatchMountEvent(const USBStorageDeviceInfo &storageDeviceInfo) - { - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = nullptr; - - if ( true == DeviceMount(storageDeviceInfo)) - { - if (usbStorageMountInfo[storageDeviceInfo.deviceName].empty()) - { - LOGERR("Empty Mount info list"); - } - else - { - usbStorageDeviceInfo.push_back(storageDeviceInfo); - /* mount info list updated, and Iterator create to send to clients */ - mountPoints = (Core::Service> \ - ::Create(usbStorageMountInfo[storageDeviceInfo.deviceName])); - LOGINFO("Device mounted"); - } - - if (mountPoints != nullptr) - { - std::list::const_iterator index(_usbStorageNotification.begin()); - while (index != _usbStorageNotification.end()) - { - mountPoints->Reset(0); - (*index)->OnDeviceMounted(storageDeviceInfo, mountPoints); - ++index; - } - mountPoints->Release(); - } - } - else - { - LOGERR("Failed to mount device %s",storageDeviceInfo.deviceName.c_str()); - } - } - - void USBMassStorageImplementation::DispatchUnMountEvent(USBStorageDeviceInfo &storageDeviceInfo) - { - Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator* mountPoints = nullptr; - auto mountInfoList = usbStorageMountInfo.find(storageDeviceInfo.deviceName); - int returnValue; - bool success = false; - - if (mountInfoList == usbStorageMountInfo.end()) - { - string deviceName = storageDeviceInfo.deviceName; - - auto it = std::find_if(usbStorageDeviceInfo.begin(), usbStorageDeviceInfo.end(), [deviceName](const USBStorageDeviceInfo& item){ - return item.deviceName == deviceName; - }); - if (it != usbStorageDeviceInfo.end()) - { - usbStorageDeviceInfo.erase(it); - } - - LOGINFO("StorageInfo removed, but Mount Info is empty"); - } - else - { - for (const auto& mountInfo : mountInfoList->second) - { - if ((returnValue = umount(mountInfo.mountPath.c_str())) == 0) - { - LOGINFO("Unmount successful"); - if (rmdir(mountInfo.mountPath.c_str()) != 0) - { - LOGERR("Failed to remove mount path: %s",mountInfo.mountPath.c_str()); - } - success = true; - } - else - { - LOGERR("Failed to unmount: %s, error %d",mountInfo.mountPath.c_str(),returnValue); - } - } - } - - if ( success ) - { - mountPoints = Core::Service> \ - ::Create(mountInfoList->second); - - if (mountPoints != nullptr) - { - std::list::const_iterator index(_usbStorageNotification.begin()); - while (index != _usbStorageNotification.end()) - { - mountPoints->Reset(0); - (*index)->OnDeviceUnmounted(storageDeviceInfo, mountPoints); - ++index; - } - mountPoints->Release(); - } - usbStorageMountInfo.erase(mountInfoList); - - string deviceName = storageDeviceInfo.deviceName; - - auto it = std::find_if(usbStorageDeviceInfo.begin(), usbStorageDeviceInfo.end(), [deviceName](const USBStorageDeviceInfo& item){ - return item.deviceName == deviceName; - }); - if (it != usbStorageDeviceInfo.end()) - { - usbStorageDeviceInfo.erase(it); - } - } - - } - - void USBMassStorageImplementation::MountDevicesOnBootUp() - { - Exchange::IUSBDevice::IUSBDeviceIterator* devices = nullptr; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - - if (nullptr == _remoteUSBDeviceObject) - { - LOGERR("USBDeviceObject is null"); - } - else if ( Core::ERROR_NONE != _remoteUSBDeviceObject->GetDeviceList(devices)) - { - LOGERR("Device list is empty or GetDeviceList() got failed"); - } - else if (nullptr != devices) - { - while (devices->Next(actual_usbDevice_dev_list) == true) - { - if (LIBUSB_CLASS_MASS_STORAGE == actual_usbDevice_dev_list.deviceClass) - { - USBStorageDeviceInfo storageDeviceInfo = {}; - if (actual_usbDevice_dev_list.devicePath.empty()) - { - LOGERR("device path is empty"); - continue; - } - storageDeviceInfo.deviceName = actual_usbDevice_dev_list.deviceName; - storageDeviceInfo.devicePath = actual_usbDevice_dev_list.devicePath; - LOGINFO("Device path[%s] Name[%s]",storageDeviceInfo.devicePath.c_str(),storageDeviceInfo.deviceName.c_str()); - - /* storage info list updated */ - usbStorageDeviceInfo.push_back(storageDeviceInfo); - if (true == DeviceMount(storageDeviceInfo)) - { - LOGINFO("Device is mounted Successfully"); - } - } - else - { - LOGWARN("[%s] is not a storage device",actual_usbDevice_dev_list.devicePath.c_str()); - } - } - } - } - - Core::hresult USBMassStorageImplementation::GetDeviceList(Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator*& deviceInfo) const - { - uint32_t errorCode = Core::ERROR_GENERAL; - bool emptyList = false; - - if (usbStorageDeviceInfo.empty()) - { - Exchange::IUSBDevice::IUSBDeviceIterator* devices = nullptr; - Exchange::IUSBDevice::USBDevice actual_usbDevice_dev_list = {0}; - emptyList = true; - - LOGINFO("usbStorageDeviceInfo list is Empty, Getting from USBDevice Plugin"); - - if (nullptr == _remoteUSBDeviceObject) - { - LOGERR("USBDeviceObject is null"); - } - else if ( Core::ERROR_NONE != _remoteUSBDeviceObject->GetDeviceList(devices)) - { - LOGERR("Device list is Empty or get failed"); - } - else if (nullptr != devices) - { - while (devices->Next(actual_usbDevice_dev_list) == true) - { - if (LIBUSB_CLASS_MASS_STORAGE == actual_usbDevice_dev_list.deviceClass) - { - USBStorageDeviceInfo storageDeviceInfo = {}; - - if (actual_usbDevice_dev_list.devicePath.empty()) - { - LOGERR("device path is empty"); - continue; - } - - if ( nullptr == USBMassStorageImplementation::_instance) - { - LOGERR("instance is null"); - } - else - { - storageDeviceInfo.deviceName = actual_usbDevice_dev_list.deviceName; - storageDeviceInfo.devicePath = actual_usbDevice_dev_list.devicePath; - LOGINFO("Device path[%s] Name[%s]",storageDeviceInfo.devicePath.c_str(),storageDeviceInfo.deviceName.c_str()); - - /* storage info list updated */ - USBMassStorageImplementation::_instance->usbStorageDeviceInfo.push_back(storageDeviceInfo); - emptyList = false; - } - } - else - { - LOGWARN("%s is not a storage device",actual_usbDevice_dev_list.devicePath.c_str()); - } - } - - errorCode = Core::ERROR_NONE; - devices->Release(); - } - } - - if ( false == emptyList ) - { - deviceInfo = Core::Service> \ - ::Create(usbStorageDeviceInfo); - errorCode = Core::ERROR_NONE; - } - return errorCode; - } - - Core::hresult USBMassStorageImplementation::GetMountPoints(const string &deviceName, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator*& mountPoints) const - { - uint32_t errorCode = Core::ERROR_GENERAL; - if (deviceName.empty()) - { - errorCode = Core::ERROR_INVALID_PARAMETER; - } - else - { - auto it = USBMassStorageImplementation::_instance->usbStorageMountInfo.find(deviceName); - if (it == USBMassStorageImplementation::_instance->usbStorageMountInfo.end()) - { - auto itr = std::find_if(usbStorageDeviceInfo.begin(), usbStorageDeviceInfo.end(), [deviceName](const USBStorageDeviceInfo& item){ - return item.deviceName == deviceName; - }); - - if (itr != usbStorageDeviceInfo.end()) - { - USBStorageDeviceInfo storageDeviceInfo = *itr; - if ( nullptr == USBMassStorageImplementation::_instance ) - { - LOGERR("instance is null"); - } - else if ( true == USBMassStorageImplementation::_instance->DeviceMount(storageDeviceInfo)) - { - if (USBMassStorageImplementation::_instance->usbStorageMountInfo[storageDeviceInfo.deviceName].empty()) - { - LOGERR("Empty Mount info list"); - } - else - { - /* mount info list updated, and Iterator create to send to clients */ - mountPoints = (Core::Service> \ - ::Create(USBMassStorageImplementation::_instance->usbStorageMountInfo[storageDeviceInfo.deviceName])); - - LOGINFO("Device mount info list"); - } - errorCode = Core::ERROR_NONE; - } - } - else - { - LOGERR("Mount info not found for device %s",deviceName.c_str()); - errorCode = ERROR_INVALID_DEVICENAME; - } - } - else - { - mountPoints = Core::Service> \ - ::Create(it->second); - errorCode = Core::ERROR_NONE; - } - } - return errorCode; - } - - Core::hresult USBMassStorageImplementation::GetPartitionInfo(const string &mountPath , Exchange::IUSBMassStorage::USBStoragePartitionInfo& partitionInfo ) const - { - string devicePath = ""; - uint32_t errorCode = Core::ERROR_GENERAL; - int fd = -1; - struct statvfs stat; - struct statfs buffer; - - if (mountPath.empty()) - { - errorCode = Core::ERROR_INVALID_PARAMETER; - } - else - { - for (const auto& pair : USBMassStorageImplementation::_instance->usbStorageMountInfo) - { - const auto& mountInfoList = pair.second; - - for (const auto& mountInfo : mountInfoList) - { - if (mountInfo.mountPath == mountPath) - { - devicePath = mountInfo.partitionName; - partitionInfo.fileSystem = mountInfo.fileSystem; - break; - } - } - } - - if (devicePath.empty()) - { - errorCode = ERROR_INVALID_MOUNTPOINT; - LOGERR("device path is not found in list"); - } - else - { - LOGINFO("Partition path: %s, Mount path: %s",devicePath.c_str(),mountPath.c_str()); - - if (statfs(mountPath.c_str(), &buffer) != 0) - { - LOGERR("statfs failed, error %s",strerror(errno)); - } - else if (statvfs(mountPath.c_str(), &stat) != 0) - { - LOGERR("statfs failed, error %s",strerror(errno)); - } - else if ((fd = open(devicePath.c_str(), O_RDONLY)) == -1) - { - LOGERR( "Failed to open device:%s" , mountPath.c_str()); - } - else - { - uint64_t size = 0; - - partitionInfo.startSector = 0; - - if (ioctl(fd, BLKGETSIZE64, &size) != 0) - { - LOGERR("Failed to get partition size, error %s",strerror(errno)); - } - else if (ioctl(fd, BLKGETSIZE, &partitionInfo.numSectors) != 0) { - LOGERR("Failed to get number of sector, error %s",strerror(errno)); - } - else if (ioctl(fd, BLKSSZGET, &partitionInfo.sectorSize) != 0) { - LOGERR("Failed to get sector size, error %s",strerror(errno)); - } - else - { - partitionInfo.totalSpace = ((uint64_t)stat.f_blocks * stat.f_frsize) / ((uint64_t)1024 * 1024); // MB - partitionInfo.availableSpace = ((uint64_t)stat.f_bfree * stat.f_frsize) / ((uint64_t)1024 * 1024); // MB - partitionInfo.usedSpace = partitionInfo.totalSpace - partitionInfo.availableSpace; - size /= (1024 * 1024); // Convert to MB - partitionInfo.size = size; - - LOGINFO("f_blocks %lu. f_frsize %lu",(long)stat.f_blocks, (long)stat.f_frsize); - - LOGINFO("PartitionInfo, fileSystem[%u],partition size[%lu MB] numSectors[%lu] sectorSize[%u]totalSpace[%u]usedSpace[%u]availableSpace[%u]", - partitionInfo.fileSystem,(long)size, (long)partitionInfo.numSectors, partitionInfo.sectorSize,partitionInfo.totalSpace,partitionInfo.usedSpace,partitionInfo.availableSpace); - - errorCode = Core::ERROR_NONE; - } - close(fd); - } - } - } - return errorCode; - } - - void USBMassStorageImplementation::OnDevicePluggedIn(const USBDevice &device) - { - if ( LIBUSB_CLASS_MASS_STORAGE == device.deviceClass ) - { - USBStorageDeviceInfo storageDeviceInfo = {}; - bool alreadyMounted = true; - - if (device.devicePath.empty()) - { - LOGERR("device path is empty"); - } - else - { - auto mountInfoList = USBMassStorageImplementation::_instance->usbStorageMountInfo.find(storageDeviceInfo.deviceName); - - if (mountInfoList != USBMassStorageImplementation::_instance->usbStorageMountInfo.end()) - { - if (mountInfoList->second.empty()) - { - alreadyMounted = false; - } - } - else - { - alreadyMounted = false; - } - } - - if ( false == alreadyMounted ) - { - if ( nullptr == USBMassStorageImplementation::_instance) - { - LOGERR("instance is null"); - } - else - { - storageDeviceInfo.devicePath = device.devicePath; - storageDeviceInfo.deviceName = device.deviceName; - LOGINFO("Device path[%s] Name[%s]",storageDeviceInfo.devicePath.c_str(),storageDeviceInfo.deviceName.c_str()); - Core::IWorkerPool::Instance().Submit(USBMassStorageImplementation::Job::Create(USBMassStorageImplementation::_instance, - USBMassStorageImplementation::USB_STORAGE_EVENT_MOUNT, - storageDeviceInfo)); - } - } - else - { - LOGERR("Device is already mounted"); - } - } - else - { - LOGWARN("%s is not a storage device",device.devicePath.c_str()); - } - } - - void USBMassStorageImplementation::OnDevicePluggedOut(const USBDevice &device) - { - if ( LIBUSB_CLASS_MASS_STORAGE == device.deviceClass ) - { - USBStorageDeviceInfo storageDeviceInfo = {}; - - storageDeviceInfo.devicePath = device.devicePath; - storageDeviceInfo.deviceName = device.deviceName; - - LOGINFO("Device path[%s] Name[%s]",storageDeviceInfo.devicePath.c_str(),storageDeviceInfo.deviceName.c_str()); - - Core::IWorkerPool::Instance().Submit(USBMassStorageImplementation::Job::Create(USBMassStorageImplementation::_instance, - USBMassStorageImplementation::USB_STORAGE_EVENT_UNMOUNT, - storageDeviceInfo)); - } - else - { - LOGWARN("%s is not a storage device",device.devicePath.c_str()); - } - } - - bool USBMassStorageImplementation::directoryExists(const string& path) - { - struct stat info; - int ret = stat(path.c_str(), &info); - return ((ret == 0 ) && (info.st_mode & S_IFDIR)); - } - - } -} - diff --git a/USBMassStorage/USBMassStorageImplementation.h b/USBMassStorage/USBMassStorageImplementation.h deleted file mode 100755 index 260ae24..0000000 --- a/USBMassStorage/USBMassStorageImplementation.h +++ /dev/null @@ -1,187 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include "Module.h" -#include -#include -#include -#include - -#include "tracing/Logging.h" -#include - -#include -#include -#include -#include "libusb.h" - -#include -#include -#include -using std::ofstream; -#include -#include -#include - -#undef MS_RDONLY -#include - -using USBDevice = WPEFramework::Exchange::IUSBDevice::USBDevice; -using USBStorageFileSystem = WPEFramework::Exchange::IUSBMassStorage::USBStorageFileSystem; -using USBStorageDeviceInfo = WPEFramework::Exchange::IUSBMassStorage::USBStorageDeviceInfo; -using USBStorageMountFlags = WPEFramework::Exchange::IUSBMassStorage::USBStorageMountFlags; - -namespace WPEFramework { -namespace Plugin { - class USBMassStorageImplementation : public Exchange::IUSBMassStorage, - public Exchange::IConfiguration { - private: - class USBDeviceNotification : public Exchange::IUSBDevice::INotification { - private: - USBDeviceNotification(const USBDeviceNotification&) = delete; - USBDeviceNotification& operator=(const USBDeviceNotification&) = delete; - - public: - explicit USBDeviceNotification(USBMassStorageImplementation& parent) - : _parent(parent) - { - } - ~USBDeviceNotification() override = default; - - void OnDevicePluggedIn(const USBDevice &device) - { - _parent.OnDevicePluggedIn(device); - } - - void OnDevicePluggedOut(const USBDevice &device) - { - _parent.OnDevicePluggedOut(device); - } - - BEGIN_INTERFACE_MAP(USBDeviceNotification) - INTERFACE_ENTRY(Exchange::IUSBDevice::INotification) - END_INTERFACE_MAP - - private: - USBMassStorageImplementation& _parent; - }; - public: - // We do not allow this plugin to be copied !! - USBMassStorageImplementation(); - ~USBMassStorageImplementation() override; - - static USBMassStorageImplementation* instance(USBMassStorageImplementation *USBMassStorageImpl = nullptr); - - // We do not allow this plugin to be copied !! - USBMassStorageImplementation(const USBMassStorageImplementation&) = delete; - USBMassStorageImplementation& operator=(const USBMassStorageImplementation&) = delete; - - BEGIN_INTERFACE_MAP(USBMassStorageImplementation) - INTERFACE_ENTRY(Exchange::IUSBMassStorage) - INTERFACE_ENTRY(Exchange::IConfiguration) - END_INTERFACE_MAP - - public: - enum Event - { - USB_STORAGE_EVENT_MOUNT, - USB_STORAGE_EVENT_UNMOUNT - }; - - class EXTERNAL Job : public Core::IDispatch { - protected: - Job(USBMassStorageImplementation* usbMass_StorageImplementation, Event event, - USBStorageDeviceInfo params) - : _usbMass_StorageImplementation(usbMass_StorageImplementation) - , _event(event) - , _params(params) { - if (_usbMass_StorageImplementation != nullptr) { - _usbMass_StorageImplementation->AddRef(); - } - } - - public: - Job() = delete; - Job(const Job&) = delete; - Job& operator=(const Job&) = delete; - ~Job() { - if (_usbMass_StorageImplementation != nullptr) { - _usbMass_StorageImplementation->Release(); - } - } - - public: - static Core::ProxyType Create(USBMassStorageImplementation* usb_mass_storageImplementation, Event event, USBStorageDeviceInfo params ) { -#ifndef USE_THUNDER_R4 - return (Core::proxy_cast(Core::ProxyType::Create(usb_mass_storageImplementation, event, params))); -#else - return (Core::ProxyType(Core::ProxyType::Create(usb_mass_storageImplementation, event, params))); -#endif - } - - virtual void Dispatch() { - _usbMass_StorageImplementation->Dispatch(_event, _params); - } - private: - USBMassStorageImplementation *_usbMass_StorageImplementation; - const Event _event; - USBStorageDeviceInfo _params; - }; - public: - virtual Core::hresult Register(Exchange::IUSBMassStorage::INotification *notification ) override ; - virtual Core::hresult Unregister(Exchange::IUSBMassStorage::INotification *notification ) override; - - Core::hresult GetDeviceList(Exchange::IUSBMassStorage::IUSBStorageDeviceInfoIterator*& deviceInfo) const override; - Core::hresult GetMountPoints(const string &deviceName, Exchange::IUSBMassStorage::IUSBStorageMountInfoIterator*& mountPoints) const override; - Core::hresult GetPartitionInfo(const string &mountPath , Exchange::IUSBMassStorage::USBStoragePartitionInfo& partitionInfo ) const override; - - // IConfiguration methods - uint32_t Configure(PluginHost::IShell* service) override; - - static USBMassStorageImplementation* _instance; - static bool directoryExists(const string& path); - - void OnDevicePluggedIn(const USBDevice &device); - void OnDevicePluggedOut(const USBDevice &device); - void registerEventHandlers(); - - private: - std::list usbStorageDeviceInfo; - std::map*/,std::list> usbStorageMountInfo; - - mutable Core::CriticalSection _adminLock; - Exchange::IUSBDevice* _remoteUSBDeviceObject; - std::list _usbStorageNotification; - Core::Sink _USB_DeviceNotification; - bool _registeredEventHandlers; - PluginHost::IShell* _service; - - void MountDevicesOnBootUp(); - bool DeviceMount(const USBStorageDeviceInfo &storageDeviceInfo); - void Dispatch(Event event, USBStorageDeviceInfo params); - void DispatchMountEvent(const USBStorageDeviceInfo &storageDeviceInfo); - void DispatchUnMountEvent(USBStorageDeviceInfo &storageDeviceInfo); - USBStorageFileSystem GetFileSystemType(__fsword_t f_type) const; - - friend class Job; - }; -} // namespace Plugin -} // namespace WPEFramework diff --git a/UserSettings/Module.cpp b/UserSettings/Module.cpp deleted file mode 100755 index 713d4b1..0000000 --- a/UserSettings/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/WebBridge/CHANGELOG.md b/WebBridge/CHANGELOG.md deleted file mode 100644 index 2e200c4..0000000 --- a/WebBridge/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -All notable changes to this RDK Service will be documented in this file. - -* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. - -* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: - * **Added** for new features. - * **Changed** for changes in existing functionality. - * **Deprecated** for soon-to-be removed features. - * **Removed** for now removed features. - * **Fixed** for any bug fixes. - * **Security** in case of vulnerabilities. - -* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. - diff --git a/WebBridge/CMakeLists.txt b/WebBridge/CMakeLists.txt deleted file mode 100644 index d2dd1db..0000000 --- a/WebBridge/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -# If not stated otherwise in this file or this component's LICENSE file the -# following copyright and licenses apply: -# -# Copyright 2020 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(PLUGIN_NAME WebBridge) -set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) - -set(PLUGIN_WEBBRIDGE_STARTUPORDER "" CACHE STRING "To configure startup order of WebBridge plugin") - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - WebBridge.cpp - Module.cpp) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins) - -install(TARGETS ${MODULE_NAME} - DESTINATION lib/${STORAGE_DIRECTORY}/plugins) - -write_config(${PLUGIN_NAME}) diff --git a/WebBridge/Module.cpp b/WebBridge/Module.cpp deleted file mode 100644 index 560b367..0000000 --- a/WebBridge/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/WebBridge/Module.h b/WebBridge/Module.h deleted file mode 100644 index 0a50d4c..0000000 --- a/WebBridge/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_WebBridge -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL diff --git a/WebBridge/WebBridge.config b/WebBridge/WebBridge.config deleted file mode 100644 index 0eb47a0..0000000 --- a/WebBridge/WebBridge.config +++ /dev/null @@ -1,6 +0,0 @@ -set (autostart false) -set (callsign org.rdk.WebBridge) - -if(PLUGIN_WEBBRIDGE_STARTUPORDER) -set (startuporder ${PLUGIN_WEBBRIDGE_STARTUPORDER}) -endif() diff --git a/WebBridge/WebBridge.cpp b/WebBridge/WebBridge.cpp deleted file mode 100644 index 7166be4..0000000 --- a/WebBridge/WebBridge.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "WebBridge.h" - -#define API_VERSION_NUMBER_MAJOR 1 -#define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 0 - -namespace WPEFramework { - -namespace { - - static Plugin::Metadata metadata( - // Version (Major, Minor, Patch) - API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, - // Preconditions - {}, - // Terminations - {}, - // Controls - {} - ); -} - -namespace Plugin { - - SERVICE_REGISTRATION(WebBridge, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); - - class EXTERNAL Registration : public Core::JSON::Container { - private: - Registration(const Registration&) = delete; - Registration& operator=(const Registration&) = delete; - - public: - Registration() - : Core::JSON::Container() - , Event() - , Callsign() - { - Add(_T("event"), &Event); - Add(_T("id"), &Callsign); - } - ~Registration() - { - } - - public: - Core::JSON::String Event; - Core::JSON::String Callsign; - }; - - // ------------------------------------------------------------------------------------------------------- - // IPluginExtended methods - // ------------------------------------------------------------------------------------------------------- - const string WebBridge::Initialize(PluginHost::IShell* service) /* override */ - { - ASSERT(_service == nullptr); - ASSERT(service != nullptr); - - string message; - - Config config; - config.FromString(service->ConfigLine()); - _skipURL = static_cast(service->WebPrefix().length()); - _callsign = service->Callsign(); - _service = service; - _timeOut = (config.TimeOut.Value() * Core::Time::TicksPerMillisecond); - - // On success return empty, to indicate there is no error text. - return (message); - } - - void WebBridge::Deinitialize(PluginHost::IShell* service) /* override */ - { - ASSERT(_service == service); - - _service = nullptr; - } - - string WebBridge::Information() const /* override */ - { - // No additional info to report. - return (string()); - } - - bool WebBridge::Attach(PluginHost::Channel& channel) /* override */ { - bool assigned = false; - - // The expectation is that the JavaScript service opens up a connection to us, so we can forward the - // incomming requests, to be handled by the Service. - if ((channel.Protocol() == _T("json")) && (_javascriptService == 0)) { - _javascriptService = channel.Id(); - assigned = true; - } - return(assigned); - } - - void WebBridge::Detach(PluginHost::Channel& channel) /* override */ { - // Hopefull this does not happen as than we are loosing the actual service :-) We could do proper error handling - // if this happens :-) - _javascriptService = 0; - } - - // ------------------------------------------------------------------------------------------------------- - // IDispatcher methods - // ------------------------------------------------------------------------------------------------------- - Core::ProxyType WebBridge::Invoke(const string& token, const uint32_t channelId, const Core::JSONRPC::Message& inbound) /* override */ - { - string method; - Registration info; - - Core::ProxyType message(PluginHost::IFactories::Instance().JSONRPC()); - string designator(inbound.Designator.Value()); - - if (inbound.Id.IsSet() == true) { - message->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - message->Id = inbound.Id.Value(); - } - - switch (Destination(designator, method)) { - case state::STATE_INCORRECT_HANDLER: - message->Error.SetError(Core::ERROR_INVALID_DESIGNATOR); - message->Error.Text = _T("Destined invoke failed."); - break; - case state::STATE_INCORRECT_VERSION: - message->Error.SetError(Core::ERROR_INVALID_SIGNATURE); - message->Error.Text = _T("Requested version is not supported."); - break; - case state::STATE_UNKNOWN_METHOD: - message->Error.SetError(Core::ERROR_UNKNOWN_KEY); - message->Error.Text = _T("Unknown method."); - break; - case state::STATE_REGISTRATION: - info.FromString(inbound.Parameters.Value()); - Subscribe(channelId, info.Event.Value(), info.Callsign.Value(), *message); - break; - case state::STATE_UNREGISTRATION: - info.FromString(inbound.Parameters.Value()); - Unsubscribe(channelId, info.Event.Value(), info.Callsign.Value(), *message); - break; - case state::STATE_EXISTS: - message->Result = Core::NumberType(Core::ERROR_UNKNOWN_KEY).Text(); - break; - case state::STATE_NONE_EXISTING: - message->Result = Core::NumberType(Core::ERROR_NONE).Text(); - break; - case state::STATE_CUSTOM: - // Let's on behalf of the request forward it and update - uint32_t newId = Core::InterlockedIncrement(_sequenceId); - Core::Time waitTill = Core::Time::Now() + _timeOut; - - _pendingRequests.emplace(std::piecewise_construct, - std::forward_as_tuple(newId), - std::forward_as_tuple(channelId, message->Id.Value(), waitTill)); - - message->Id = newId; - message->Parameters = inbound.Parameters; - message->Designator = inbound.Designator; - - TRACE(Trace::Information, (_T("Request: [%d] from [%d], method: [%s]"), message->Id.Value(), channelId, method.c_str())); - - _service->Submit(_javascriptService, Core::ProxyType(message)); - - // Wait for ID to return, we can not report anything back yet... - message.Release(); - - if (_timeOut != 0) { - _cleaner.Schedule(waitTill); - } - - break; - } - - return message; - } - - void WebBridge::Activate(PluginHost::IShell* /* service */) /* override */ { - // We did what we needed to do in the Intialize. - } - - void WebBridge::Deactivate() /* override */ { - // We did what we needed to do in the Deintialize. - } - - // ------------------------------------------------------------------------------------------------------- - // IWebSocket methods - // ------------------------------------------------------------------------------------------------------- - Core::ProxyType WebBridge::Inbound(const string& /* identifier */) /* override */{ - // There is a message coming in over the JSON WebSocket path!, give it storage space.. - return (Core::ProxyType(PluginHost::IFactories::Instance().JSONRPC())); - } - - Core::ProxyType WebBridge::Inbound(const uint32_t ID, const Core::ProxyType& element) /* override */ { - - Core::ProxyType message(element); - - ASSERT(message.IsValid() == true); - - if (message.IsValid()) { - - if (message->Id.IsSet() == false) { - - string eventName(message->Method()); - - // Check for control messages between server and us.. - if (InternalMessage(message) == false) { - - // This is an event, we need event handling.. - _adminLock.Lock(); - - ObserverMap::iterator index = _observers.find(eventName); - - if (index != _observers.end()) { - for (const Observer& entry : index->second) { - Core::ProxyType outbound(PluginHost::IFactories::Instance().JSONRPC()); - outbound->Designator = (entry.Designator().empty() == false ? entry.Designator() + '.' + eventName : eventName); - outbound->Parameters = message->Parameters.Value(); - - _service->Submit(entry.Id(), Core::ProxyType(outbound)); - } - } - - _adminLock.Unlock(); - } - } - else { - uint32_t requestId, channelId = 0; - - // This is the response to an invoked method, Let's see who should get this repsonse :-) - _adminLock.Lock(); - PendingMap::iterator index = _pendingRequests.find(message->Id.Value()); - if (index != _pendingRequests.end()) { - channelId = index->second.ChannelId(); - requestId = index->second.SequenceId(); - _pendingRequests.erase(index); - } - _adminLock.Unlock(); - - if (channelId != 0) { - TRACE(Trace::Information, (_T("Response: [%d] to [%d]"), requestId, channelId)); - - // Oke, there is someone waiting for a response! - message->Id = requestId; -#ifndef USE_THUNDER_R4 - _service->Submit(channelId, Core::proxy_cast(message)); -#else - _service->Submit(channelId, Core::ProxyType(message)); -#endif /* USE_THUNDER_R4 */ - } - } - } - - // We will never report anything back here :-) - return (Core::ProxyType()); - } - - // ------------------------------------------------------------------------------------------------------- - // Private methods - // ------------------------------------------------------------------------------------------------------- - void WebBridge::Cleanup() { - // Lets see if there are still any pending request we should report Missing In Action :-) - Core::Time now (Core::Time::Now()); - Core::Time nextSlot; - - _adminLock.Lock(); - PendingMap::iterator index(_pendingRequests.begin()); - while (index != _pendingRequests.end()) { - if (now >= index->second.Issued()) { - // Send and Error to the requester.. - Core::ProxyType message(PluginHost::IFactories::Instance().JSONRPC()); - message->Error.SetError(Core::ERROR_TIMEDOUT); - message->Error.Text = _T("There is no response form the server within time!!!"); - message->Id = index->second.SequenceId(); - - TRACE(Trace::Warning, (_T("Got a timeout on channelId [%d] for request [%d]"), index->second.ChannelId(), message->Id.Value())); - - _service->Submit(index->second.ChannelId(), Core::ProxyType(message)); - index = _pendingRequests.erase(index); - } - else { - if ((nextSlot.IsValid() == false) || (nextSlot > index->second.Issued())) { - nextSlot = index->second.Issued(); - } - index++; - } - } - _adminLock.Unlock(); - - if (nextSlot.IsValid()) { - _cleaner.Schedule(nextSlot); - } - } - - bool WebBridge::InternalMessage(const Core::ProxyType& message) { - bool result = false; - - string eventName(message->Method()); - - if (eventName == "registerjsonrpcmethods") { - result = true; - Core::JSON::ArrayType parameter; - parameter.FromString(message->Parameters.Value()); - Core::JSON::ArrayType::Iterator index(parameter.Elements()); - - _supportedVersions.clear(); - - while (index.Next() == true) { - string entry = index.Current().Value(); - uint8_t version = Core::JSONRPC::Message::Version(entry); - string method = Core::JSONRPC::Message::Method(entry); - VersionMap::iterator placement = _supportedVersions.find(version); - - if (placement == _supportedVersions.end()) { - auto newEntry = _supportedVersions.emplace(std::piecewise_construct, - std::forward_as_tuple(version), - std::forward_as_tuple()); - - newEntry.first->second.push_back(method); - } - else if (std::find(placement->second.begin(), placement->second.end(), method) == placement->second.end()) { - // Check if this label does not already exist - placement->second.push_back(method); - } - } - } - - return (result); - } - -} // namespace Plugin -} // namespace WPEFramework diff --git a/WebBridge/WebBridge.h b/WebBridge/WebBridge.h deleted file mode 100644 index 51a5fa1..0000000 --- a/WebBridge/WebBridge.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" - -namespace WPEFramework { -namespace Plugin { - - class WebBridge : - public PluginHost::IPluginExtended, - public PluginHost::IDispatcher, - public PluginHost::IWebSocket - { - private: - enum class state { - STATE_INCORRECT_HANDLER, - STATE_INCORRECT_VERSION, - STATE_UNKNOWN_METHOD, - STATE_REGISTRATION, - STATE_UNREGISTRATION, - STATE_EXISTS, - STATE_NONE_EXISTING, - STATE_CUSTOM - }; - class Observer { - public: - Observer(const Observer&) = delete; - Observer& operator=(const Observer&) = delete; - - Observer(const uint32_t id, const string& designator) - : _id(id) - , _designator(designator) - { - } - ~Observer() = default; - - public: - bool operator==(const Observer& rhs) const - { - return ((rhs._id == _id) && (rhs._designator == _designator)); - } - bool operator!=(const Observer& rhs) const - { - return (!operator==(rhs)); - } - - uint32_t Id() const - { - return (_id); - } - const string& Designator() const - { - return (_designator); - } - - private: - uint32_t _id; - string _designator; - }; - class Request { - public: - Request() = delete; - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - - Request(const uint32_t channelId, const uint32_t sequenceId, const Core::Time& timeOut) - : _channelId(channelId) - , _sequenceId(sequenceId) - , _issued(timeOut) { - } - ~Request() = default; - - public: - uint32_t ChannelId() const { - return (_channelId); - } - uint32_t SequenceId() const { - return (_sequenceId); - } - const Core::Time& Issued() const { - return (_issued); - } - - private: - uint32_t _channelId; - uint32_t _sequenceId; - Core::Time _issued; - }; - class Cleaner { - private: - using BaseClass = Core::IWorkerPool::JobType; - - public: - Cleaner(const Cleaner&) = delete; - Cleaner& operator=(const Cleaner&) = delete; - - Cleaner(WebBridge& parent) : _parent(parent) { - } - ~Cleaner() = default; - - public: - void Dispatch() { - _parent.Cleanup(); - } - - private: - WebBridge& _parent; - }; - - using ObserverList = std::list; - using ObserverMap = std::map; - using MethodList = std::vector; - using VersionMap = std::map; - using PendingMap = std::map; - - public: - class Config : public Core::JSON::Container { - public: - Config() - : Core::JSON::Container() - , TimeOut(3000) - { - Add(_T("timeout"), &TimeOut); - } - ~Config() override = default; - - public: - Core::JSON::String Bind; - Core::JSON::DecUInt16 TimeOut; - }; - - public: - WebBridge(const WebBridge&) = delete; - WebBridge& operator=(const WebBridge&) = delete; - - #ifdef __WINDOWS__ - #pragma warning(disable: 4355) - #endif - WebBridge() - : _adminLock() - , _skipURL(0) - , _service(nullptr) - , _callsign() - , _supportedVersions() - , _observers() - , _pendingRequests() - , _javascriptService(0) - , _sequenceId(1) - , _timeOut(0) - , _cleaner(*this) - { - } - #ifdef __WINDOWS__ - #pragma warning(default: 4355) - #endif - ~WebBridge() override = default; - - BEGIN_INTERFACE_MAP(WebBridge) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IPluginExtended) - INTERFACE_ENTRY(PluginHost::IWebSocket) - INTERFACE_ENTRY(PluginHost::IDispatcher) - END_INTERFACE_MAP - - public: - // IPlugin methods - // ------------------------------------------------------------------------------------------------------- - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - const string Initialize(PluginHost::IShell* service) override; - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - void Deinitialize(PluginHost::IShell* service) override; - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - string Information() const override; - - // IDispatcher - // ------------------------------------------------------------------------------------------------------- - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - Core::ProxyType Invoke(const string& token, const uint32_t channelId, const Core::JSONRPC::Message& message) override; - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - void Activate(PluginHost::IShell* service) override; - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - void Deactivate() override; - - // IPluginExtended - // ------------------------------------------------------------------------------------------------------- - //! ================================== CALLED ON COMMUNICATION THREAD ===================================== - bool Attach(PluginHost::Channel& channel) override; - //! ================================== CALLED ON COMMUNICATION THREAD ===================================== - void Detach(PluginHost::Channel& channel) override; - - // IWebSocket - // ------------------------------------------------------------------------------------------------------- - //! ================================== CALLED ON COMMUNICATION THREAD ===================================== - Core::ProxyType Inbound(const string& identifier) override; - //! ==================================== CALLED ON THREADPOOL THREAD ====================================== - Core::ProxyType Inbound(const uint32_t ID, const Core::ProxyType& element) override; - - - private: - void Cleanup(); - bool InternalMessage(const Core::ProxyType& message); - - bool HasMethodSupport(const VersionMap::const_iterator& index, const string& method) const { - bool result = false; - - if (index != _supportedVersions.cend()) { - result = (std::find(index->second.cbegin(), index->second.cend(), method) != index->second.cend()); - } - else { - VersionMap::const_iterator index = _supportedVersions.begin(); - - while ((result == false) && (index != _supportedVersions.end())) { - result = (std::find(index->second.cbegin(), index->second.cend(), method) != index->second.cend()); - index++; - } - } - - return (result); - } - state Destination(const string& designator, string& handler) const - { - state result = state::STATE_INCORRECT_HANDLER; - string callsign(Core::JSONRPC::Message::Callsign(designator)); - - // If the message is routed through the controlelr, the callsign is empty by now! - if ((callsign.empty()) || (callsign == _callsign)) { - // Seems we are on the right handler.. - // now see if someone supports this version - uint8_t version = Core::JSONRPC::Message::Version(designator); - VersionMap::const_iterator methods = _supportedVersions.cend(); - - // See if there was a version given.. - if (version != static_cast(~0)) { - methods = _supportedVersions.find(version); - if (methods == _supportedVersions.cend()) { - result = state::STATE_INCORRECT_VERSION; - } - } - - if (result == state::STATE_INCORRECT_HANDLER) { - string method = Core::JSONRPC::Message::Method(designator); - - if (method == _T("register")) { - result = state::STATE_REGISTRATION; - } - else if (method == _T("unregister")) { - result = state::STATE_UNREGISTRATION; - } - else if (method == _T("exists")) { - result = HasMethodSupport(methods, method) ? state::STATE_EXISTS : state::STATE_NONE_EXISTING; - } - else if (HasMethodSupport(methods, method) == true) { - result = state::STATE_CUSTOM; - handler = method; - } - else { - result = state::STATE_UNKNOWN_METHOD; - } - } - } - return (result); - } - void Subscribe(const uint32_t channelId, const string& eventName, const string& callsign, Core::JSONRPC::Message& response) - { - _adminLock.Lock(); - - ObserverMap::iterator index = _observers.find(eventName); - - if (index == _observers.end()) { - _observers[eventName].emplace_back(channelId, callsign); - response.Result = _T("0"); - } - else if (std::find(index->second.begin(), index->second.end(), Observer(channelId, callsign)) == index->second.end()) { - index->second.emplace_back(channelId, callsign); - response.Result = _T("0"); - } - else { - response.Error.SetError(Core::ERROR_DUPLICATE_KEY); - response.Error.Text = _T("Duplicate registration. Only 1 remains!!!"); - } - - _adminLock.Unlock(); - } - void Unsubscribe(const uint32_t channelId, const string& eventName, const string& callsign, Core::JSONRPC::Message& response) - { - _adminLock.Lock(); - - ObserverMap::iterator index = _observers.find(eventName); - - if (index != _observers.end()) { - ObserverList& clients = index->second; - ObserverList::iterator loop = clients.begin(); - Observer key(channelId, callsign); - - while ((loop != clients.end()) && (*loop != key)) { - loop++; - } - - if (loop != clients.end()) { - clients.erase(loop); - if (clients.empty() == true) { - _observers.erase(index); - } - response.Result = _T("0"); - } - } - - if (response.Result.IsSet() == false) { - response.Error.SetError(Core::ERROR_UNKNOWN_KEY); - response.Error.Text = _T("Registration not found!!!"); - } - - _adminLock.Unlock(); - } - - private: - Core::CriticalSection _adminLock; - uint8_t _skipURL; - PluginHost::IShell* _service; - string _callsign; - VersionMap _supportedVersions; - ObserverMap _observers; - PendingMap _pendingRequests; - uint32_t _javascriptService; - uint32_t _sequenceId; - uint32_t _timeOut; - Core::WorkerPool::JobType _cleaner; - }; - -} // namespace Plugin -} // namespace WPEFramework diff --git a/WebBridge/js/WebBridgeClient.js b/WebBridge/js/WebBridgeClient.js deleted file mode 100644 index cf1a3c6..0000000 --- a/WebBridge/js/WebBridgeClient.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -const client = new WebSocket("ws://localhost:10001/jsonrpc", "json"); -client.onopen = function(e) { - console.log("client connected"); - - let req = {}; - req.jsonrpc = "2.0" - req.id = 10 - req.method = "org.rdk.Calculator.1.add"; - req.params = [ 2, 2 ] - - const s = JSON.stringify(req); - console.log("send:" + s) - client.send(s) -} -client.onmessage = function(msg) { - const req = JSON.parse(msg.data) - console.log("recv:" + JSON.stringify(req)) -} diff --git a/WebBridge/js/WebBridgeSDK.js b/WebBridge/js/WebBridgeSDK.js deleted file mode 100644 index 64b828b..0000000 --- a/WebBridge/js/WebBridgeSDK.js +++ /dev/null @@ -1,246 +0,0 @@ -/** - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -const request_state = { - PENDING: 'pending' -}; - -class JsonRpcClient -{ - constructor(uri, protocols) { - this._uri = uri; - this._websocket = null; - this._next_request_id = 1; - this._outstanding_requests = {}; - this._json_rpc_version = "2.0"; - this._sub_protocols = protocols; - } - - open() { - let promise = new Promise((resolve, reject) => { - const self = this; - self._websocket = new WebSocket(self._uri, self._sub_protocols); - self._websocket.onopen = function(e) { - resolve(e); - }; - self._websocket.onerror = function(e) { - reject(e); - }; - self._websocket.onmessage = function(e) { - self._onIncomingMessage(e); - }; - }); - return promise; - } - - sendRequest(method_name, method_params, user_data) { - const self = this; - const request_id = self._next_request_id++; - const request_message = { - jsonrpc: self._json_rpc_version, - id: request_id, - method: method_name, - params: method_params - }; - - let async_ctx = {}; - async_ctx.state = request_state.PENDING; - async_ctx.user_data = user_data; - async_ctx.resolve = null; - async_ctx.reject = null; - - let promise = new Promise((resolve, reject) => { - async_ctx.resolve = resolve; - async_ctx.reject = reject; - }); - - self._outstanding_requests[request_id] = async_ctx; - self.send(request_message); - - return promise; - } - - notify(event_data) { - send(event_data); - } - - send(message) { - const self = this; - const json_text = JSON.stringify(message); - console.log(">>> " + json_text); - self._websocket.send(json_text); - } - - _onIncomingMessage(e) { - const self = this; - console.log("<<< " + e.data); - const json = JSON.parse(e.data); - if (json.id in self._outstanding_requests) { - const async_ctx = self._outstanding_requests[json.id]; - if (async_ctx.state == request_state.PENDING) { - const e_res = {}; - e_res.response = json; - e_res.user_data = async_ctx.user_data; - async_ctx.resolve(e_res); - } - delete self._outstanding_requests[json.id]; - } - else { - // TODO: we just got a message with an id that isn't in the - // outstanding requests map - } - } -} - -class Service { - constructor(name) { - this.service_name = name; - this.methods = {}; - this._send_event_function = function() {}; - } - - registerMethod(method_name, method_version, method) { - const self = this; - const fq_method_name = method_version + "." + method_name; - self.methods[fq_method_name] = method; - } - - notify(event_data) { - } - - _callMethodByName(method_name, json_rpc_params) { - const self = this; - if (self.methods[method_name]) { - return self.methods[method_name](json_rpc_params); - } - else { - return Promise.reject("method " + method_name + " not found"); - } - } -} - -class ServiceManager { - constructor(conf) { - this._json_rpc_client = null; - this._services = {}; - this._conf = null; - } - - open(conf) { - const self = this; - self._conf = conf; - - const uri = "ws:" + self._conf.host + ":" + self._conf.port + "/jsonrpc"; - self._json_rpc_client = new JsonRpcClient(uri, ["json"]); - return self._json_rpc_client.open(); - } - - registerService(service) { - const self = this; - self._services[service.service_name] = { - service: service, - websocket: null, - send: null - }; - self._controllerCloneService(service.service_name).then((e) => { - if (e.response.result) { - self._controllerActivateService(e.user_data).then((e) => { - self._connectService(e.user_data); - }); - } - else { - // TODO: - } - }); - } - - _connectService(service_name) { - const self = this; - const service = self._services[service_name]; - const service_endpoint = "ws://" + this._conf.host + ":" + this._conf.port + "/Service/" + service_name; - service.websocket = new WebSocket(service_endpoint, ["json"]); - service.send = function(obj) { - const json_text = JSON.stringify(obj); - console.log(">>> " + json_text); - service.websocket.send(json_text); - } - service.websocket.onopen = function(e) { - const method_list = Object.keys(service.service.methods); - const params = { - jsonrpc: "2.0", - method: "1.registerjsonrpcmethods", - params: method_list - }; - service.send(params); - } - service.websocket.onmessage = function(e) { - let res = {}; - res.jsonrpc = "2.0"; - - let req = null; - try { - console.log("<<< " + e.data); - req = JSON.parse(e.data); - res.id = req.id; - service.service._callMethodByName(req.method, req.params).then(value => { - res.result = value; - self._sendResponse(service.websocket, res); - }).catch(ex => { - res.error = {}; - res.error.message = "" + ex; - res.error.code = -32000; - try { - self._sendResponse(service.websocket, res); - } - catch (send_ex) { - console.log(send_ex); - } - }); - } - catch (dispatch_ex) { - console.log(send_ex.stack); - } - }; - } - - _controllerActivateService(service_name) { - const self = this; - const params = { - callsign: service_name - }; - return self._json_rpc_client.sendRequest("Controller.1.activate", params, service_name); - } - - _sendResponse(soc, res) { - const json_text = JSON.stringify(res); - console.log(">>> " + json_text); - soc.send(json_text); - } - - _controllerCloneService(service_name) { - const self = this; - const params = { - callsign: "org.rdk.WebBridge", - newcallsign: service_name - }; - return self._json_rpc_client.sendRequest("Controller.1.clone", params, service_name); - } -} - -// exports.Service = Service -// exports.ServiceManager = ServiceManager diff --git a/WebBridge/js/WebBridgeServer.js b/WebBridge/js/WebBridgeServer.js deleted file mode 100644 index 21af1f7..0000000 --- a/WebBridge/js/WebBridgeServer.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright 2023 Comcast Cable Communications Management, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -class CalculatorService extends Service { - constructor() { - super("org.rdk.Calculator"); - this.registerMethod('add', 1, this.add.bind(this)); - this.registerMethod('sub', 1, this.sub.bind(this)); - } - - add(params) { - console.log("add(" + JSON.stringify(params) + ")") - return new Promise((resolve, reject) => { - let sum = params.reduce((a, b) => a + b, 0); - resolve(sum) - }); - } - - sub(params) { - console.log("sub(" + JSON.stringify(params) + ")") - return new Promise((resolve, reject) => { - let diff = params[0] - params[1] - resolve(diff) - }); - } -} - -const service_manager = new ServiceManager() -service_manager.open({"host":"127.0.0.1", "port":10001}) - .then(() => { - service_manager.registerService(new CalculatorService()) - }).catch(ex => { - console.log(ex.error); - }); diff --git a/WebBridge/js/calc_server.html b/WebBridge/js/calc_server.html deleted file mode 100644 index 254437e..0000000 --- a/WebBridge/js/calc_server.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - Check the console window. - - diff --git a/build_dependencies.sh b/build_dependencies.sh index 1b38fea..359161c 100644 --- a/build_dependencies.sh +++ b/build_dependencies.sh @@ -10,7 +10,7 @@ cd ${GITHUB_WORKSPACE} #1. Install Dependencies and packages apt update -apt install -y libsqlite3-dev libcurl4-openssl-dev valgrind lcov clang libsystemd-dev libboost-all-dev libwebsocketpp-dev meson libcunit1 libcunit1-dev curl protobuf-compiler-grpc libgrpc-dev libgrpc++-dev libunwind-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev +apt install -y libcurl4-openssl-dev valgrind lcov clang libsystemd-dev libboost-all-dev libwebsocketpp-dev meson curl libunwind-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev pip install jsonref ############################ diff --git a/cov_build.sh b/cov_build.sh index d42ab63..6782f31 100644 --- a/cov_build.sh +++ b/cov_build.sh @@ -5,11 +5,11 @@ set -e GITHUB_WORKSPACE="${PWD}" ls -la ${GITHUB_WORKSPACE} ############################ -# Build entservices-infra -echo "buliding entservices-infra" +# Build entservices-usersettings +echo "building entservices-usersettings" cd ${GITHUB_WORKSPACE} -cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/entservices-infra \ +cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/entservices-usersettings \ -DUSE_THUNDER_R4=ON \ -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" \ -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" \ @@ -21,10 +21,7 @@ cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/entservices-infra \ -DRDK_SERVICES_COVERITY=ON \ -DRDK_SERVICES_L1_TEST=ON \ -DDS_FOUND=ON \ --DPLUGIN_USBDEVICE=ON \ --DPLUGIN_USB_MASS_STORAGE=ON \ --DPLUGIN_OCICONTAINER=ON \ --DPLUGIN_TELEMETRY=ON \ +-DPLUGIN_USERSETTINGS=ON \ -DCMAKE_CXX_FLAGS="-DEXCEPTIONS_ENABLE=ON \ -I ${GITHUB_WORKSPACE}/entservices-testframework/Tests/headers \ -I ${GITHUB_WORKSPACE}/entservices-testframework/Tests/headers/audiocapturemgr \ @@ -64,6 +61,6 @@ cmake -G Ninja -S "$GITHUB_WORKSPACE" -B build/entservices-infra \ -DHAS_RBUS -DDISABLE_SECURITY_TOKEN -DENABLE_DEVICE_MANUFACTURER_INFO -DUSE_THUNDER_R4=ON -DTHUNDER_VERSION=4 -DTHUNDER_VERSION_MAJOR=4 -DTHUNDER_VERSION_MINOR=4" \ -cmake --build build/entservices-infra --target install +cmake --build build/entservices-usersettings --target install echo "======================================================================================" exit 0 diff --git a/helpers/BaseEventDelegate.h b/helpers/BaseEventDelegate.h deleted file mode 100644 index 1122a1f..0000000 --- a/helpers/BaseEventDelegate.h +++ /dev/null @@ -1,239 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2020 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#ifndef __BASEEVENTDELEGATE_H__ -#define __BASEEVENTDELEGATE_H__ -#include "StringUtils.h" -#include -#include "UtilsLogging.h" -#include "UtilsCallsign.h" -#include -#include -#include - -using namespace WPEFramework; - -class BaseEventDelegate -{ -public: - class EXTERNAL EventDelegateDispatchJob : public Core::IDispatch - { - public: - EventDelegateDispatchJob(BaseEventDelegate *delegate, const string &event, const string &payload) - : mDelegate(*delegate), mEvent(event), mPayload(payload) {} - - EventDelegateDispatchJob() = delete; - EventDelegateDispatchJob(const EventDelegateDispatchJob &) = delete; - EventDelegateDispatchJob &operator=(const EventDelegateDispatchJob &) = delete; - ~EventDelegateDispatchJob() - { - } - - static Core::ProxyType Create(BaseEventDelegate *parent, - const string &event, const string &payload) - { - return (Core::ProxyType(Core::ProxyType::Create(parent, event, payload))); - } - - virtual void Dispatch() - { - mDelegate.DispatchToAppNotifications(mEvent, mPayload); - } - - private: - BaseEventDelegate &mDelegate; - string mEvent; - string mPayload; - }; - - BaseEventDelegate() : mRegisteredNotifications(), - mRegisterMutex() - { - } - - ~BaseEventDelegate() - { - // Cleanup registered notifications - for (auto &entry : mRegisteredNotifications) - { - for (auto emitter : entry.second) - { - emitter->Release(); - } - } - - mRegisteredNotifications.clear(); - } - - virtual bool HandleEvent(Exchange::IAppNotificationHandler::IEmitter *cb, const string &event, const bool listen, bool ®istrationError) = 0; - - bool Dispatch(const string &event, const string &payload) - { - LOGDBG("Dispatching %s with payload %s", event.c_str(), payload.c_str()); - - // Check if Notification is registered if not return - if (!IsNotificationRegistered(event)) - { - LOGDBG("Notification %s is not registered", event.c_str()); - return false; - } - - Core::IWorkerPool::Instance().Submit(EventDelegateDispatchJob::Create(this, event, payload)); - - return true; - } - - bool DispatchToAppNotifications(const string &event, const string &payload) - { - - auto emitters = GetEmittersForNotification(event); - if (!emitters.empty()) - { - LOGDBG("Using registered emitter for event %s", event.c_str()); - for (auto emitter : emitters) - { - emitter->Emit(event, payload, ""); - emitter->Release(); - } - return true; - } - - LOGERR("No emitter found for event %s", event.c_str()); - return false; - } - - // new method to register notifications - // which accepts a string and adds it to the mRegisteredNotifications vector - void AddNotification(const string &event, Exchange::IAppNotificationHandler::IEmitter *cb) - { - ASSERT(cb != nullptr); - string event_l = StringUtils::toLower(event); - std::lock_guard lock(mRegisterMutex); - auto it = mRegisteredNotifications.find(event_l); - // add to the existing one - if (it != mRegisteredNotifications.end()) - { - // check if cb is already registered - if (it->second.find(cb) != it->second.end()) - { - LOGDBG("Notification %s already registered for this emitter", event_l.c_str()); - } - else - { - it->second.insert(cb); - cb->AddRef(); - LOGDBG("Added additional emitter for notification = %s", event_l.c_str()); - } - } - else - { - std::unordered_set emitters; - emitters.insert(cb); - mRegisteredNotifications[event_l] = emitters; - cb->AddRef(); - LOGDBG("Notification registered = %s", event_l.c_str()); - } - } - - // new method to check if a notification is registered - bool IsNotificationRegistered(const string &event) - { - string event_l = StringUtils::toLower(event); - std::lock_guard lock(mRegisterMutex); - bool result = mRegisteredNotifications.find(event_l) != mRegisteredNotifications.end(); - LOGDBG("Finding notification = %s result=%s", event_l.c_str(), result ? "true" : "false"); - return result; - } - - std::unordered_set GetEmittersForNotification(const string &event) - { - string event_l = StringUtils::toLower(event); - std::unordered_set emitters; - std::lock_guard lock(mRegisterMutex); - auto it = mRegisteredNotifications.find(event_l); - if (it != mRegisteredNotifications.end()) - { - emitters = it->second; - for (auto emitter : emitters) - { - emitter->AddRef(); - } - } - return emitters; - } - - // new method remove the notification - void RemoveNotification(const string &event, Exchange::IAppNotificationHandler::IEmitter *cb) - { - ASSERT(cb != nullptr); - string event_l = StringUtils::toLower(event); - std::lock_guard lock(mRegisterMutex); - if (!event_l.empty()) - { - // Remove specific emitter for the event - auto it = mRegisteredNotifications.find(event_l); - if (it != mRegisteredNotifications.end()) - { - auto emitter = it->second.find(cb); - if (emitter != it->second.end()) - { - (*emitter)->Release(); - it->second.erase(emitter); - LOGDBG("Removed emitter for notification = %s", event_l.c_str()); - } - - // If no more emitters for the event, remove the event entry - if (it->second.empty()) - { - mRegisteredNotifications.erase(it); - LOGDBG("No more emitters for notification = %s, event entry removed", event_l.c_str()); - } - } - } - else - { // For empty event, remove all events for the cb emitter - - for (auto it = mRegisteredNotifications.begin(); it != mRegisteredNotifications.end();) - { - auto emitter = it->second.find(cb); - if (emitter != it->second.end()) - { - (*emitter)->Release(); - it->second.erase(emitter); - LOGDBG("Removed emitter for notification = %s", it->first.c_str()); - } - - // If no more emitters for the event, remove the event entry - if (it->second.empty()) - { - LOGDBG("No more emitters for notification = %s, event entry removed", it->first.c_str()); - it = mRegisteredNotifications.erase(it); - } - else - { - ++it; - } - } - } - } - -private: - std::map> mRegisteredNotifications; - std::mutex mRegisterMutex; -}; -#endif diff --git a/helpers/ContextUtils.h b/helpers/ContextUtils.h deleted file mode 100644 index de50033..0000000 --- a/helpers/ContextUtils.h +++ /dev/null @@ -1,57 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef __CONTEXTUTILS_H__ -#define __CONTEXTUTILS_H__ -#include -#include - -#include "UtilsCallsign.h" -using namespace WPEFramework; -using namespace std; -class ContextUtils { - public: - // Implement a static method which accepts a Exchange::IAppNotifications::Context object and - // converts it into Exchange::IAppGateway::Context object - static Exchange::GatewayContext ConvertNotificationToAppGatewayContext(const Exchange::IAppNotifications::AppNotificationContext& notificationsContext){ - Exchange::GatewayContext appGatewayContext; - // Perform the conversion logic here - appGatewayContext.requestId = notificationsContext.requestId; - appGatewayContext.connectionId = notificationsContext.connectionId; - appGatewayContext.appId = notificationsContext.appId; - return appGatewayContext; - } - - // Implement a static method which accepts a Exchange::IAppGateway::Context object and - // converts it into Exchange::IAppNotifications::Context object - static Exchange::IAppNotifications::AppNotificationContext ConvertAppGatewayToNotificationContext(const Exchange::GatewayContext& appGatewayContext, const string& origin){ - Exchange::IAppNotifications::AppNotificationContext notificationsContext; - // Perform the conversion logic here - notificationsContext.requestId = appGatewayContext.requestId; - notificationsContext.connectionId = appGatewayContext.connectionId; - notificationsContext.appId = appGatewayContext.appId; - notificationsContext.origin = origin; - return notificationsContext; - } - - static bool IsOriginGateway(const string& origin) { - return origin == APP_GATEWAY_CALLSIGN; - } -}; -#endif diff --git a/helpers/ObjectUtils.h b/helpers/ObjectUtils.h deleted file mode 100644 index 3217cca..0000000 --- a/helpers/ObjectUtils.h +++ /dev/null @@ -1,89 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef __OBJECTUTILS_H__ -#define __OBJECTUTILS_H__ -using namespace WPEFramework; -using namespace std; -class ObjectUtils { - public: - // Implement a static method which accepts a JsonObject and a key string - // and returns true if the key exists in the JsonObject and its value is boolean - static bool HasBooleanEntry(const JsonObject& obj, const string& key, bool& resultValue) { - if (!obj.HasLabel(key.c_str())) { - return false; - } - const auto& value = obj[key.c_str()]; - if (value.IsNull()) { - return false; - } else if(value.Content() == Core::JSON::Variant::type::BOOLEAN) { - // add the resultValue - resultValue = value.Boolean(); - return true; - } - return false; - } - - // implement a new method which accepts a key and boolean value uses CreateBooleanObject to create a JsonObject - // and then serializes it to a string and returns the string - static string CreateBooleanJsonString(const string& key, const bool value) { - JsonObject obj = CreateBooleanObject(key, value); - string resultStr; - obj.ToString(resultStr); - return resultStr; - } - - // Implement a new method which creates a JsonObject value for a given key and boolean value - static JsonObject CreateBooleanObject(const string& key, const bool value) { - JsonObject obj; - ObjectUtils::AddBooleanEntry(obj, key, value); - return obj; - } - - // Implement a static method which accepts a JsonObject, a key string and a boolean value - // and adds the key-value pair to the JsonObject - static void AddBooleanEntry(JsonObject& obj, const string& key, const bool value) { - obj[key.c_str()] = value; - } - - // Implement a static method which accepts a JsonObject and a key string - // and returns true if the key exists in the JsonObject and its value is string - static bool HasStringEntry(const JsonObject& obj, const string& key, string& resultValue) { - if (!obj.HasLabel(key.c_str())) { - return false; - } - const auto& value = obj[key.c_str()]; - if (value.IsNull()) { - return false; - } else if(value.Content() == Core::JSON::Variant::type::STRING) { - // add the resultValue - resultValue = value.String(); - return true; - } - return false; - } - - // Implement a new static method which accepts a boolean and returns a - // serialized string "true" or "false" - static string BoolToJsonString(const bool value) { - return value ? "true" : "false"; - } -}; -#endif - diff --git a/helpers/PowerManagerInterface.h b/helpers/PowerManagerInterface.h deleted file mode 100755 index 1486299..0000000 --- a/helpers/PowerManagerInterface.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#pragma once - -#include "PluginInterfaceBuilder.h" - -using PowerManagerInterfaceBuilder = WPEFramework::Plugin::PluginInterfaceBuilder; -using PowerManagerInterfaceRef = WPEFramework::Plugin::PluginInterfaceRef; diff --git a/helpers/StreamJSONOneShot.h b/helpers/StreamJSONOneShot.h deleted file mode 100644 index 7988a7c..0000000 --- a/helpers/StreamJSONOneShot.h +++ /dev/null @@ -1,266 +0,0 @@ -// Forked one-shot variant of StreamJSONType to workaround issue with streaming JSON parsing -// of invalid json data that causes infinite loops. -// Original StreamJSONType tries to parse incoming data in a loop until all data is consumed, -// which can lead to infinite loops if the data is malformed. This variant only attempts to parse the data once per call. -// - Parses incoming buffer in a single call, instead of looping. -// - Public API mirrors the original StreamJSONType. - -#pragma once - -#include -#include -#include - -namespace WPEFramework { -namespace Core { - - template - class StreamJSONOneShotType { - private: - using ParentClass = StreamJSONOneShotType; - - class SerializerImpl { - public: - SerializerImpl() = delete; - SerializerImpl(const SerializerImpl&) = delete; - SerializerImpl& operator=(const SerializerImpl&) = delete; - - SerializerImpl(ParentClass& parent, const uint8_t slotSize) - : _parent(parent) - , _adminLock() - , _sendQueue(slotSize) - , _offset(0) - { - } - - ~SerializerImpl() { - _sendQueue.Clear(); - } - - bool IsIdle() const { - return (_sendQueue.Count() == 0); - } - - bool Submit(const ProxyType& entry) { - _adminLock.Lock(); - _sendQueue.Add(const_cast&>(entry)); - const bool trigger = (_sendQueue.Count() == 1); - _adminLock.Unlock(); - return trigger; - } - - uint16_t Serialize(uint8_t* stream, const uint16_t length) const { - uint16_t loaded = 0; - - _adminLock.Lock(); - if (_sendQueue.Count() > 0) { - loaded = Serialize(_sendQueue[0], stream, length); - // If fully sent or we’re not in a partial-send state, notify and pop - if ((_offset == 0) || (loaded != length)) { - Core::ProxyType current = _sendQueue[0]; - _parent.Send(current); - _sendQueue.Remove(0); - _offset = 0; - } - } - _adminLock.Unlock(); - - return loaded; - } - - private: - // Overloads for JSON text vs MessagePack - inline uint16_t Serialize(const Core::ProxyType& source, - uint8_t* stream, const uint16_t length) const { - return source->Serialize(reinterpret_cast(stream), length, _offset); - } - - inline uint16_t Serialize(const Core::ProxyType& source, - uint8_t* stream, const uint16_t length) const { - return source->Serialize(stream, length, _offset); - } - - private: - ParentClass& _parent; - mutable Core::CriticalSection _adminLock; - mutable Core::ProxyList _sendQueue; - mutable uint32_t _offset; - }; - - class DeserializerImpl { - public: - DeserializerImpl() = delete; - DeserializerImpl(const DeserializerImpl&) = delete; - DeserializerImpl& operator=(const DeserializerImpl&) = delete; - - DeserializerImpl(ParentClass& parent, const uint8_t slotSize) - : _parent(parent) - , _factory(slotSize) - , _current() - , _offset(0) - { - } - - DeserializerImpl(ParentClass& parent, ALLOCATOR allocator) - : _parent(parent) - , _factory(allocator) - , _current() - , _offset(0) - { - } - - bool IsIdle() const { - return (_current.IsValid() == false); - } - - // One-shot entry: parse current buffer once. - uint16_t Deserialize(const uint8_t* stream, const uint16_t length) { - uint16_t loaded = 0; - - if (_current.IsValid() == false) { - _current = Core::ProxyType(_factory.Element(EMPTY_STRING)); - _offset = 0; - } - - if (_current.IsValid() == true) { - loaded = Deserialize(_current, stream, length); - - // If message finished (offset reset by callee) or not all bytes used, - // deliver the element now and reset. - if ((_offset == 0) || (loaded != length)) { - _parent.Received(_current); - _current.Release(); - } - } - - return loaded; - } - - private: - inline uint16_t Deserialize(const Core::ProxyType& source, - const uint8_t* stream, const uint16_t length) { - return source->Deserialize(reinterpret_cast(stream), length, _offset); - } - - inline uint16_t Deserialize(const Core::ProxyType& source, - const uint8_t* stream, const uint16_t length) { - return source->Deserialize(stream, length, _offset); - } - - private: - ParentClass& _parent; - ALLOCATOR _factory; - Core::ProxyType _current; - uint32_t _offset; - }; - - class HandlerType : public SOURCE { - public: - HandlerType() = delete; - HandlerType(const HandlerType&) = delete; - HandlerType& operator=(const HandlerType&) = delete; - - explicit HandlerType(ParentClass& parent) - : SOURCE() - , _parent(parent) { - } - - template - HandlerType(ParentClass& parent, Args... args) - : SOURCE(args...) - , _parent(parent) { - } - - ~HandlerType() override = default; - - public: - // Pass-through to parent - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override { - return _parent.SendData(dataFrame, maxSendSize); - } - - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) override { - return _parent.ReceiveData(dataFrame, receivedSize); - } - - void StateChange() override { - _parent.StateChange(); - } - - bool IsIdle() const override { - return _parent.IsIdle(); - } - - private: - ParentClass& _parent; - }; - - public: - StreamJSONOneShotType(const StreamJSONOneShotType&) = delete; - StreamJSONOneShotType& operator=(const StreamJSONOneShotType&) = delete; - - PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST) - // Constructor with external allocator - template - StreamJSONOneShotType(uint8_t slotSize, ALLOCATOR& allocator, Args... args) - : _channel(*this, args...) - , _serializer(*this, slotSize) - , _deserializer(*this, allocator) { - } - - // Constructor with slot-sized factory - template - StreamJSONOneShotType(uint8_t slotSize, Args... args) - : _channel(*this, args...) - , _serializer(*this, slotSize) - , _deserializer(*this, slotSize) { - } - POP_WARNING() - - virtual ~StreamJSONOneShotType() { - _channel.Close(Core::infinite); - } - - public: - inline SOURCE& Link() { return _channel; } - - virtual void Received(ProxyType& element) = 0; - virtual void Send(ProxyType& element) = 0; - virtual void StateChange() = 0; - - inline void Submit(const ProxyType& element) { - if (_channel.IsOpen() == true) { - if (_serializer.Submit(element)) { - _channel.Trigger(); - } - } - } - - inline uint32_t Open(const uint32_t waitTime) { return _channel.Open(waitTime); } - inline uint32_t Close(const uint32_t waitTime) { return _channel.Close(waitTime); } - inline bool IsOpen() const { return _channel.IsOpen(); } - inline bool IsClosed() const { return _channel.IsClosed(); } - inline bool IsSuspended() const { return _channel.IsSuspended(); } - - private: - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) { - return _serializer.Serialize(dataFrame, maxSendSize); - } - - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) { - return _deserializer.Deserialize(&dataFrame[0], receivedSize); - } - - bool IsIdle() const { - return (_serializer.IsIdle() && _deserializer.IsIdle()); - } - - private: - HandlerType _channel; - SerializerImpl _serializer; - DeserializerImpl _deserializer; - }; - -} // namespace Core -} // namespace WPEFramework - diff --git a/helpers/StringUtils.h b/helpers/StringUtils.h deleted file mode 100644 index 366fa5b..0000000 --- a/helpers/StringUtils.h +++ /dev/null @@ -1,60 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef __STRINGUTILS_H__ -#define __STRINGUTILS_H__ - -#include -#include -#include "UtilsLogging.h" - -using namespace std; -class StringUtils { - public: - static string toLower(const string& input) { - string result = input; - transform(result.begin(), result.end(), result.begin(), - [](unsigned char c) { return tolower(c); }); - return result; - } - - static bool rfindInsensitive(const string& reference, const string& key) { - string lowerRef = toLower(reference); - string lowerKey = toLower(key); - return lowerRef.rfind(lowerKey) != string::npos; - } - - static bool checkStartsWithCaseInsensitive(const string& method, const string& key) { - string lowerRef = toLower(method); - string lowerKey = toLower(key); - return lowerRef.rfind(lowerKey) == 0; - } - - static string extractMethodName(const string& method) { - size_t lastDot = method.rfind('.'); - if (lastDot == string::npos || lastDot + 1 >= method.length()) { - LOGERR("Invalid method format, cannot extract appId: %s", method.c_str()); - return ""; - } - string extracted = method.substr(lastDot + 1); - return StringUtils::toLower(extracted); - } -}; - -#endif \ No newline at end of file diff --git a/helpers/UtilsBIT.h b/helpers/UtilsBIT.h deleted file mode 100644 index ab6d5f1..0000000 --- a/helpers/UtilsBIT.h +++ /dev/null @@ -1,36 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include - -/* a=target variable, b=bit number to act upon 0-n */ -#define BIT_SET(a,b) ((a) |= (1ULL<<(b))) -#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b))) -#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b))) -#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1 - -#define BITMASK_SET(x, mask) ((x) |= (mask)) -#define BITMASK_CLEAR(x, mask) ((x) &= (~(mask))) -#define BITMASK_FLIP(x, mask) ((x) ^= (mask)) -#define BITMASK_CHECK_ALL(x, mask) (!(~(x) & (mask))) -#define BITMASK_CHECK_ANY(x, mask) ((x) & (mask)) - -#define GET_BITMASK(a) (((short)pow(2,a))&0xFFFF) diff --git a/helpers/UtilsCStr.h b/helpers/UtilsCStr.h deleted file mode 100644 index 0d1bbab..0000000 --- a/helpers/UtilsCStr.h +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#define C_STR(x) (x).c_str() diff --git a/helpers/UtilsCallsign.h b/helpers/UtilsCallsign.h deleted file mode 100644 index 11a580f..0000000 --- a/helpers/UtilsCallsign.h +++ /dev/null @@ -1,32 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#ifndef __UTILSCALLSIGN_H__ -#define __UTILSCALLSIGN_H__ -#define APP_GATEWAY_CALLSIGN "org.rdk.AppGateway" -#define GATEWAY_AUTHENTICATOR_CALLSIGN "org.rdk.LaunchDelegate" -#define INTERNAL_GATEWAY_CALLSIGN "org.rdk.LaunchDelegate" -#define APP_NOTIFICATIONS_CALLSIGN "org.rdk.AppNotifications" -#define APP_TO_APP_PROVIDER_CALLSIGN "org.rdk.App2AppProvider" -#define FB_PRIVACY_CALLSIGN "org.rdk.FbPrivacy" -#define FB_METRICS_CALLSIGN "org.rdk.FbMetrics" -#define ANALYTICS_PLUGIN_CALLSIGN "org.rdk.Analytics" -#endif \ No newline at end of file diff --git a/helpers/UtilsConnections.h b/helpers/UtilsConnections.h deleted file mode 100644 index 31bd2d1..0000000 --- a/helpers/UtilsConnections.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#pragma once - -#include "UtilsLogging.h" -#include - -namespace WPEFramework -{ - namespace Utils - { - - std::string ResolveQuery(const std::string &query, const std::string &key) - { - // Check if query is empty - if (query.empty()) - { - LOGWARN("Query is empty"); - return ""; - } - - // Find key position - size_t pos = query.find(key); - if (pos == std::string::npos) - { - LOGWARN("%s not found in query: %s\n", key.c_str(), query.c_str()); - return ""; - } - - std::string value = query.substr(pos + key.length()+1); - - if (value.empty()) - { - LOGERR("ResolveQuery: '%s' value missing in query: %s\n", key.c_str(), query.c_str()); - return ""; - } - - LOGINFO("ResolveQuery: Extracted %s = %s\n", key.c_str(), value.c_str()); - return value; - } - } -} \ No newline at end of file diff --git a/helpers/UtilsController.h b/helpers/UtilsController.h deleted file mode 100644 index f3729bb..0000000 --- a/helpers/UtilsController.h +++ /dev/null @@ -1,227 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include - -#ifndef DISABLE_SECURITY_TOKEN -#include -#endif - -// std -#include - -#define MAX_STRING_LENGTH 2048 - -#define SERVER_DETAILS "127.0.0.1:9998" - -using namespace WPEFramework; -using namespace std; - -namespace Utils -{ - struct SecurityToken - { - static void getSecurityToken(std::string &token) - { - static std::string sToken = ""; - static bool sThunderSecurityChecked = false; - - static std::mutex mtx; - std::unique_lock lock(mtx); - - if (sThunderSecurityChecked) - { - token = sToken; - return; - } - - sThunderSecurityChecked = true; - -#ifdef DISABLE_SECURITY_TOKEN - token = sToken; -#else - if (!isThunderSecurityConfigured()) - { - LOGINFO("Thunder Security is not enabled. Not getting token"); - token = sToken; - return; - } - - unsigned char buffer[MAX_STRING_LENGTH] = {0}; - int ret = GetSecurityToken(MAX_STRING_LENGTH, buffer); - if (ret < 0) - { - LOGERR("Error in getting token"); - } - else - { - LOGINFO("Retrieved token successfully"); - token = (char *)buffer; - sToken = token; - } -#endif - } - -#ifndef DISABLE_SECURITY_TOKEN - static size_t writeCurlResponse(void *ptr, size_t size, size_t nmemb, string stream) - { - size_t realsize = size * nmemb; - string temp(static_cast(ptr), realsize); - stream.append(temp); - return realsize; - } - - static bool isThunderSecurityConfigured() - { - bool configured = false; - long http_code = 0; - std::string jsonResp; - CURL *curl_handle = NULL; - CURLcode res = CURLE_OK; - curl_handle = curl_easy_init(); - string serialNumber = ""; - string url = "http://127.0.0.1:9998/Service/Controller/Configuration/Controller"; - if (curl_handle && - !curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()) && - !curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1) && - !curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1) && // when redirected, follow the redirections - !curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeCurlResponse) && - !curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &jsonResp)) - { - - res = curl_easy_perform(curl_handle); - if (curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code) != CURLE_OK) - { - std::cout << "curl_easy_getinfo failed\n"; - } - std::cout << "Thunder Controller Configuration ret: " << res << " http response code: " << http_code << std::endl; - curl_easy_cleanup(curl_handle); - } - else - { - std::cout << "Could not perform curl to read Thunder Controller Configuration\n"; - } - if ((res == CURLE_OK) && (http_code == 200)) - { - // check for "Security" in response - JsonObject responseJson = JsonObject(jsonResp); - if (responseJson.HasLabel("subsystems")) - { - const JsonArray subsystemList = responseJson["subsystems"].Array(); - for (int i = 0; i < subsystemList.Length(); i++) - { - string subsystem = subsystemList[i].String(); - if (subsystem == "Security") - { - configured = true; - break; - } - } - } - } - return configured; - } -#endif - - }; - - // Thunder Plugin Communication - std::shared_ptr> getThunderControllerClient(std::string callsign="") - { - - string token; - Utils::SecurityToken::getSecurityToken(token); - string query = "token=" + token; - - Core::SystemInfo::SetEnvironment(_T("THUNDER_ACCESS"), (_T(SERVER_DETAILS))); - std::shared_ptr> thunderClient = make_shared>(callsign.c_str(), "", false, query); - - return thunderClient; - } - -#ifndef USE_THUNDER_R4 - class Job : public Core::IDispatchType -#else - class Job : public Core::IDispatch -#endif /* USE_THUNDER_R4 */ - { - public: - Job(std::function work) - : _work(work) - { - } - void Dispatch() override - { - _work(); - } - - private: - std::function _work; - }; - - uint32_t getServiceState(PluginHost::IShell *shell, const string &callsign, PluginHost::IShell::state &state) - { - uint32_t result; - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) - { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } - else - { - result = Core::ERROR_NONE; - state = interface->State(); - std::cout << "IShell state " << state << " for " << callsign << std::endl; - interface->Release(); - } - return result; - } - - uint32_t activatePlugin(PluginHost::IShell *shell, const string &callsign) - { - uint32_t result = Core::ERROR_ASYNC_FAILED; - Core::Event event(false, true); - -#ifndef USE_THUNDER_R4 - Core::IWorkerPool::Instance().Submit(Core::ProxyType>(Core::ProxyType::Create([&]() - { -#else - Core::IWorkerPool::Instance().Submit(Core::ProxyType(Core::ProxyType::Create([&]() - { -#endif /* USE_THUNDER_R4 */ - auto interface = shell->QueryInterfaceByCallsign(callsign); - if (interface == nullptr) { - result = Core::ERROR_UNAVAILABLE; - std::cout << "no IShell for " << callsign << std::endl; - } else { - result = interface->Activate(PluginHost::IShell::reason::REQUESTED); - std::cout << "IShell activate status " << result << " for " << callsign << std::endl; - interface->Release(); - } - event.SetEvent(); }))); - - event.Lock(); - return result; - } - -} diff --git a/helpers/UtilsFirebolt.h b/helpers/UtilsFirebolt.h deleted file mode 100644 index 30c671c..0000000 --- a/helpers/UtilsFirebolt.h +++ /dev/null @@ -1,196 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2020 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef __UTILSFIREBOLT_H__ -#define __UTILSFIREBOLT_H__ - -#include -#include - -using namespace WPEFramework; - -#define ERROR_NOT_SUPPORTED (-50100) -#define ERROR_NOT_AVAILABLE (-50200) -#define ERROR_NOT_PERMITTED (-40300) - - -class JListenRequest: public Core::JSON::Container { - public: - Core::JSON::Boolean listen; - - JListenRequest() : Core::JSON::Container() - { - Add(_T("listen"), &listen); - } - - bool Get() const { - return listen.Value(); - } -}; - -class JListenResponse: public Core::JSON::Container { - public: - Core::JSON::String event; - Core::JSON::Boolean listening; - - JListenResponse() : Core::JSON::Container() - { - Add(_T("event"), &event); - Add(_T("listening"), &listening); - } - -}; - -struct ProviderInfo{ - uint32_t channelId{0}; - uint32_t requestId{0}; - - static ProviderInfo create(uint32_t chId, uint32_t reqId) { - ProviderInfo info; - info.channelId = chId; - info.requestId = reqId; - return info; - } -}; - -class ProviderRegistry{ - public: - void Add(const std::string& key, uint32_t chId, uint32_t reqId) { - std::lock_guard lock(mProviderMutex); - mProviderMap[key] = ProviderInfo::create(chId, reqId); - } - - void Add(const std::string& key, ProviderInfo provider) { - std::lock_guard lock(mProviderMutex); - mProviderMap[key] = provider; - } - - void Remove(const std::string& key) { - std::lock_guard lock(mProviderMutex); - mProviderMap.erase(key); - } - - void CleanupByConnectionId(const uint32_t connectionId) { - std::lock_guard lock(mProviderMutex); - for (auto it = mProviderMap.begin(); it != mProviderMap.end(); ) { - if (it->second.channelId == connectionId) { - it = mProviderMap.erase(it); - } else { - ++it; - } - } - } - - ProviderInfo Get(const std::string& key) { - ProviderInfo info; - std::lock_guard lock(mProviderMutex); - auto it = mProviderMap.find(key); - if (it != mProviderMap.end()) { - info = it->second; - } - return info; - } - - private: - std::unordered_map mProviderMap; - std::mutex mProviderMutex; -}; - -enum FireboltError { - NOT_SUPPORTED, - NOT_AVAILABLE, - NOT_PERMITTED -}; - -class ResponseUtils { - public: - static Core::hresult SetNullResponseForSuccess(const Core::hresult hResult, std::string& result) { - if (Core::ERROR_NONE == hResult && result.empty()) { - result = "null"; - } - return hResult; - } -}; - -class ErrorUtils { - public: - static std::string GetErrorMessageForFrameworkErrors(const uint32_t& errorCode, const std::string& message) { - std::string errorMessage; - Core::JSONRPC::Message::Info info; - info.SetError(errorCode); - info.Text = message; - info.ToString(errorMessage); - return errorMessage; - } - - static std::string GetFireboltError(const FireboltError& error) { - std::string errorMessage; - Core::JSONRPC::Message::Info info; - switch (error) { - case FireboltError::NOT_SUPPORTED: - info.Code = ERROR_NOT_SUPPORTED; - info.Text = "NotSupported"; - break; - case FireboltError::NOT_AVAILABLE: - info.Code = ERROR_NOT_AVAILABLE; - info.Text = "NotAvailable"; - break; - case FireboltError::NOT_PERMITTED: - info.Code = ERROR_NOT_PERMITTED; - info.Text = "NotPermitted"; - break; - default: - errorMessage = "UnknownError"; - break; - } - info.ToString(errorMessage); - return errorMessage; - } - - static void NotSupported(string& resolution) { - resolution = ErrorUtils::GetFireboltError(FireboltError::NOT_SUPPORTED); - } - - static void NotAvailable(string& resolution) { - resolution = ErrorUtils::GetFireboltError(FireboltError::NOT_AVAILABLE); - } - - static void NotPermitted(string& resolution) { - resolution = ErrorUtils::GetFireboltError(FireboltError::NOT_PERMITTED); - } - - static void CustomInitialize(const string& message, string& resolution) { - resolution = ErrorUtils::GetErrorMessageForFrameworkErrors(Core::ERROR_GENERAL, message); - } - - static void CustomInternal(const string& message, string& resolution) { - resolution = ErrorUtils::GetErrorMessageForFrameworkErrors(Core::ERROR_BAD_REQUEST, message); - } - - static void CustomBadRequest(const string& message, string& resolution) { - resolution = ErrorUtils::GetErrorMessageForFrameworkErrors(Core::ERROR_INVALID_SIGNATURE, message); - } - - static void CustomBadMethod(const string& message, string& resolution) { - resolution = ErrorUtils::GetErrorMessageForFrameworkErrors(Core::ERROR_INVALID_DESIGNATOR, message); - } - -}; - -#endif \ No newline at end of file diff --git a/helpers/UtilsIarm.h b/helpers/UtilsIarm.h deleted file mode 100644 index c9e6116..0000000 --- a/helpers/UtilsIarm.h +++ /dev/null @@ -1,90 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "UtilsLogging.h" - -#include "libIBus.h" -#include - -#define IARM_CHECK(FUNC) { \ - if ((res = FUNC) != IARM_RESULT_SUCCESS) { \ - LOGINFO("IARM %s: %s", #FUNC, \ - res == IARM_RESULT_INVALID_PARAM ? "invalid param" : ( \ - res == IARM_RESULT_INVALID_STATE ? "invalid state" : ( \ - res == IARM_RESULT_IPCCORE_FAIL ? "ipcore fail" : ( \ - res == IARM_RESULT_OOM ? "oom" : "unknown")))); \ - } \ - else \ - { \ - LOGINFO("IARM %s: success", #FUNC); \ - } \ -} - -namespace Utils { -struct IARM { - static bool init() - { - IARM_Result_t res; - bool result = false; - - if (isConnected()) { - LOGINFO("IARM already connected"); - result = true; - } else { - unsigned int retryCount = 0; - do - { - res = IARM_Bus_Init(NAME); - LOGINFO("IARM_Bus_Init: %d", res); - if (res == IARM_RESULT_SUCCESS || res == IARM_RESULT_INVALID_STATE /* already inited or connected */) { - res = IARM_Bus_Connect(); - LOGINFO("IARM_Bus_Connect: %d", res); - if (res == IARM_RESULT_SUCCESS || res == IARM_RESULT_INVALID_STATE /* already connected or not inited */) { - result = isConnected(); - LOGERR("ARM_Bus_Connect result: %d res: %d retryCount :%d ",result, res, retryCount); - } else { - LOGERR("IARM_Bus_Connect failure:result :%d res: %d retryCount :%d ",result, res, retryCount); - } - } else { - LOGERR("IARM_Bus_Init failure: result :%d res: %d retryCount :%d",result, res,retryCount); - } - - if(result == false) usleep(100000); - - }while((result == false) && (retryCount++ < 20)); - } - - return result; - } - - static bool isConnected() - { - IARM_Result_t res; - int isRegistered = 0; - res = IARM_Bus_IsConnected(NAME, &isRegistered); - LOGINFO("IARM_Bus_IsConnected: res:%d isRegistered (%d)", res, isRegistered); - - return (isRegistered == 1); - } - - static constexpr const char* NAME = "Thunder_Plugins"; -}; -} diff --git a/helpers/UtilsInputValidator.h b/helpers/UtilsInputValidator.h deleted file mode 100644 index 4904942..0000000 --- a/helpers/UtilsInputValidator.h +++ /dev/null @@ -1,351 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2023 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Utils { - -#define NON_COPYABLE(Type) \ - Type(Type &) = delete; \ - Type& operator=(Type &) = delete;\ - -#define NON_MOVABLE(Type) \ - Type(Type &&) = delete; \ - Type& operator=(Type &&) = delete;\ - -template -class ExpectedValues -{ -private: - enum Type - { - None, - Discrete, - Range, - RegExp - }; - -public: - ExpectedValues() = default; - - ExpectedValues &operator=(const ExpectedValues ©) - { - m_type = copy.m_type; - switch (m_type) - { - case Type::Discrete: - for (auto &value : copy.m_values) - m_values.emplace(value); - break; - case Type::Range: - m_range = copy.m_range; - break; - case Type::RegExp: - m_regex = copy.m_regex; - break; - case None: - default: - break; - } - - return *this; - }; - ExpectedValues(const ExpectedValues ©) - { - operator=(copy); - } - - ExpectedValues &operator=(ExpectedValues &©) - { - std::swap(m_type, copy.m_type); - switch (m_type) - { - case Type::Discrete: - m_values = std::move(copy.m_values); - break; - case Type::Range: - m_range = copy.m_range; - break; - case Type::RegExp: - m_regex = std::move(copy.m_regex); - break; - case None: - default: - break; - } - - return *this; - }; - ExpectedValues(ExpectedValues &©) - { - operator=(std::forward>(copy)); - }; - - virtual ~ExpectedValues(){}; - - ExpectedValues(T min, T max) : m_type(Range), m_range({min, max}) {} - ExpectedValues(std::string regexStr) : m_type(RegExp), m_regex(std::regex(std::move(regexStr))) {} - ExpectedValues(std::regex regex) : m_type(RegExp), m_regex(std::move(regex)) {} - ExpectedValues(std::set values) : m_type(Discrete), m_values(std::move(values)) {} - - ExpectedValues(std::initializer_list values) : m_type(Discrete), m_values(std::move(values)) {} - ExpectedValues(std::initializer_list values) : m_type(Discrete) - { - for (auto *value : values) { - if (!value) - continue; - m_values.emplace(std::string(value)); - } - } - - ExpectedValues(std::vector values) : m_type(Discrete), m_values(std::move(values)) {} - ExpectedValues(std::vector values) : m_type(Discrete) - { - for (auto *value : values) { - if (!value) - continue; - m_values.emplace(std::string(value)); - } - } - - inline bool validate(const T &value) const - { - switch (m_type) - { - case Type::Discrete: - return std::find(m_values.begin(), m_values.end(), value) != m_values.end(); - case Type::Range: - return value >= m_range.m_min && value <= m_range.m_max; - case Type::RegExp: - return regexMatch(value); - case None: - default: - return true; - } - } - - inline bool validate(const char *value) - { - return value ? validate(std::string(value)) : false; - } - -private: - inline bool regexMatch(const std::string &value) const - { - return std::regex_match(value, m_regex); - } - - template - inline bool regexMatch(const U &value) const - { - return regexMatch(std::to_string(value)); - } - -private: - Type m_type{None}; - - struct - { - T m_min; - T m_max; - } m_range; - std::set m_values; - std::regex m_regex; -}; - -struct ValidatorBase -{ - virtual ~ValidatorBase(){}; -}; - -template -class Validator : public ValidatorBase -{ - using FunctionType = std::function; - - enum Type - { - None, - UseExpectedValues, - CustomValidation - }; - -public: - NON_COPYABLE(Validator); - NON_MOVABLE(Validator); - virtual ~Validator(){}; - - inline static std::shared_ptr create(ExpectedValues &&expectedValues) - { - return std::shared_ptr(static_cast(new Validator(std::forward>(expectedValues)))); - } - - inline static std::shared_ptr create(FunctionType &&func) - { - return std::shared_ptr(static_cast(new Validator(std::forward(func)))); - } - -public: - inline virtual bool validate(const T &value) - { - switch (m_type) - { - case Type::CustomValidation: - return m_func(value); - break; - case Type::UseExpectedValues: - return m_expectedValues.validate(value); - break; - case None: - default: - return false; - } - } - -protected: - Validator() : m_type(Type::None) {} - -private: - Validator(ExpectedValues expectedValues) : m_type(UseExpectedValues), m_expectedValues(std::move(expectedValues)) {} - Validator(std::function func) : m_type(CustomValidation), m_func(std::move(func)) {} - -private: - Type m_type; - - union - { - ExpectedValues m_expectedValues; - std::function m_func; - }; -}; - -class ValidationManager -{ -public: - using ValidatorMap = std::map>>; - using LoggerFunction = void(*)(const char *log); - -public: - inline void addValidator(std::string name, std::shared_ptr validator) - { - m_validators[name].emplace_back(std::move(validator)); - } - - template - inline void addValidator(std::string name, ExpectedValues &&expectedValues) - { - addValidator(name, Validator::create(std::forward>(expectedValues))); - } - - template > - inline void addValidator(std::string name, FunctionType &&func) - { - addValidator(name, Validator::create(std::forward(func))); - } - - template - inline bool validate(std::string name, const T &value) - { - auto it = m_validators.find(name); - if (it != m_validators.end()) - { - for (auto &strValidatorBase : it->second) - { - auto *validator = dynamic_cast *>(strValidatorBase.get()); - if (validator == nullptr || !validator->validate(value)) - { - std::stringstream ss; - if (!validator) - ss << "Validator not found for key \"" << name << "\" with type \"" << typeid(T).name() << "\"" << std::endl; - ss << "Validation failed for key \"" << name << "\" with type \"" << typeid(T).name() << "\" & value \"" << value << "\"" << std::endl; - - if (m_logger) - m_logger(ss.str().c_str()); - else - std::cout << ss.str(); - - return false; - } - } - - return true; - } - - return false; - } - - inline bool validate(std::string name, const char *value) - { - return value ? validate(name, std::string(value)) : false; - } - - void setLogger(LoggerFunction logger) - { - m_logger = logger; - } - -private: - ValidatorMap m_validators; - LoggerFunction m_logger { nullptr }; -}; - -} // namespace Utils - -#if 0 -namespace { - using namespace Utils; - - template - class MyCustomValidator : public Validator - { - public: - NON_COPYABLE(MyCustomValidator); - NON_MOVABLE(MyCustomValidator); - virtual ~MyCustomValidator(){}; - - inline static std::shared_ptr create() - { - return std::shared_ptr(static_cast(new MyCustomValidator())); - } - - public: - inline virtual bool validate(const T &value) override - { - return true; - } - - private: - MyCustomValidator() : Validator() {} - }; - - ValidationManager validator; - validator.addValidator("key", MyCustomValidator::create()); -} -#endif - diff --git a/helpers/UtilsJsonrpcDirectLink.h b/helpers/UtilsJsonrpcDirectLink.h deleted file mode 100644 index 66f9f77..0000000 --- a/helpers/UtilsJsonrpcDirectLink.h +++ /dev/null @@ -1,183 +0,0 @@ -/** - * If not stated otherwise in this file or this component's LICENSE - * file the following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -#pragma once - -#include "UtilsLogging.h" -#include - -namespace WPEFramework -{ - namespace Utils - { - - uint32_t GetThunderSecurityToken(PluginHost::IShell *service, std::string &token) - { - uint32_t result = Core::ERROR_GENERAL; - auto security = service->QueryInterfaceByCallsign("SecurityAgent"); - if (security != nullptr) - { - string payload = "http://localhost"; - if (security->CreateToken( - static_cast(payload.length()), - reinterpret_cast(payload.c_str()), - token) == Core::ERROR_NONE) - { - LOGINFO("Got security token\n"); - result = Core::ERROR_NONE; - } - else - { - LOGINFO("Failed to get security token\n"); - } - security->Release(); - } - else - { - LOGINFO("No security agent\n"); - result = Core::ERROR_NONE; // No security agent, so no token needed - } - - return result; - } - - struct JSONRPCDirectLink - { - private: - uint32_t mId{0}; - std::string mCallSign{}; - std::string mThunderSecurityToken{}; - PluginHost::ILocalDispatcher *mDispatcher{nullptr}; - - bool ToString(std::string &out, const std::string &in) const - { - out = in; - return true; - } - - bool ToString(std::string &out, const Core::JSON::IElement &in) const - { - std::string text; - if (in.ToString(text) == false) - { - LOGERR("Failed to serialize parameters!!!"); - return false; - } - out = std::move(text); - return true; - } - - bool FromString(std::string &out, const std::string &in) const - { - out = in; - return true; - } - - bool FromString(Core::JSON::IElement& response, const std::string &in) const - { - Core::OptionalType error; - if (response.FromString(in, error) == false) - { - LOGERR("Failed to parse response!!! Error: %s", error.Value().Message().c_str()); - return false; - } - return true; - } - - public: - JSONRPCDirectLink(PluginHost::IShell *service, const std::string &callsign, const std::string &token = "") - : mCallSign(callsign) - , mThunderSecurityToken(token) - { - if (service) - { - mDispatcher = service->QueryInterfaceByCallsign(mCallSign); - } - } - - JSONRPCDirectLink(PluginHost::IShell *service) - : JSONRPCDirectLink(service, "Controller") - { - } - - ~JSONRPCDirectLink() - { - if (mDispatcher) - { - mDispatcher->Release(); - } - } - - template - Core::hresult Invoke(const string &method, const PARAMETERS ¶meters, RESPONSE &response) - { - if (mDispatcher == nullptr) - { - LOGERR("No JSON RPC dispatcher for %s", mCallSign.c_str()); - return Core::ERROR_GENERAL; - } - - const uint32_t channelId = ~0; - uint32_t id = ++mId; - std::string designator = mCallSign + ".1." + method; - std::string parametersStr; - if (ToString(parametersStr, parameters) == false) - { - return Core::ERROR_GENERAL; - } - - string responseStr = ""; - Core::hresult result = Core::ERROR_BAD_REQUEST; - - if (mDispatcher != nullptr) - { - if (mDispatcher->Local() != nullptr) - { - result = mDispatcher->Invoke(channelId, id, mThunderSecurityToken, designator, parametersStr, responseStr); - - if (result != Core::ERROR_NONE) - { - LOGERR("Call failed: %s (parameters: %s) error: %d, response: %s", designator.c_str(), parametersStr.c_str(), result, responseStr.c_str()); - } - - if (FromString(response, responseStr) == false) - { - result = Core::ERROR_GENERAL; - } - } - } - - return result; - } - }; - - std::shared_ptr GetThunderControllerClient(PluginHost::IShell *service, std::string callsign="") - { - static std::string sThunderSecurityToken(""); - static bool sThunderSecurityTokenAcquired(false); - - if (sThunderSecurityTokenAcquired == false) { - sThunderSecurityTokenAcquired = - (GetThunderSecurityToken(service, sThunderSecurityToken) == Core::ERROR_NONE); - } - - return std::make_shared(service, callsign, sThunderSecurityToken); - } - - } -} diff --git a/helpers/UtilsLOG_MILESTONE.h b/helpers/UtilsLOG_MILESTONE.h deleted file mode 100644 index 45ef5f8..0000000 --- a/helpers/UtilsLOG_MILESTONE.h +++ /dev/null @@ -1,24 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "rdk_logger_milestone.h" - -#define LOG_MILESTONE(milestone) logMilestone(milestone); diff --git a/helpers/UtilsLibraryLoader.h b/helpers/UtilsLibraryLoader.h deleted file mode 100644 index f8734ee..0000000 --- a/helpers/UtilsLibraryLoader.h +++ /dev/null @@ -1,98 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2025 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include - -#ifndef LIBLOADER_DFL_DIR -#error LIBLOADER_DFL_DIR is not defined -#endif - -namespace Utils { - -class LibraryLoader -{ -public: - enum ErrorCode { - NO_ERROR = 0, - LIBRARY_PATH_EMPTY, - LIBRARY_LOAD_FAILURE - }; - - LibraryLoader() = default; - ~LibraryLoader() - { - if (mLibraryHandle != nullptr) { - dlclose(mLibraryHandle); - } - } - - ErrorCode Load(const std::string &libraryPath, std::string &errorMessage) - { - dlerror(); - if (libraryPath.empty()) { - errorMessage = "Library path is empty."; - return ErrorCode::LIBRARY_PATH_EMPTY; - } - - if (mLibraryHandle != nullptr) { - dlclose(mLibraryHandle); - mLibraryHandle = nullptr; - } - - std::string fullPath = std::string(LIBLOADER_DFL_DIR) + "/" + libraryPath; - - mLibraryHandle = dlopen(fullPath.c_str(), RTLD_LAZY); - if (mLibraryHandle == nullptr) { - errorMessage = dlerror(); - return ErrorCode::LIBRARY_LOAD_FAILURE; - } - - return ErrorCode::NO_ERROR; - } - - template - std::shared_ptr CreateShared(Args&&... args, std::string &errorMessage) - { - using CreatorFunc = T* (*)(Args...); - - if (mLibraryHandle == nullptr) { - errorMessage = "Library not loaded."; - return nullptr; - } - - dlerror(); - CreatorFunc func = reinterpret_cast(dlsym(mLibraryHandle, "Create")); - if (func == nullptr) { - errorMessage = dlerror(); - return nullptr; - } - return std::shared_ptr(func(std::forward(args)...)); - } - -private: - - void* mLibraryHandle = nullptr; -}; - -} \ No newline at end of file diff --git a/helpers/UtilsProcess.h b/helpers/UtilsProcess.h deleted file mode 100755 index 3cad6e8..0000000 --- a/helpers/UtilsProcess.h +++ /dev/null @@ -1,92 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace Utils -{ -/** -* @brief Kill all the processes with the given process name -* @param[in] input_pname - The given process name -* @return true if any process with the given name was killed, otherwise false is returned -*/ -bool killProcess(string& input_pname) -{ - PROCTAB* proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS); - proc_t proc_info = {0}; - bool ret_value = false; - - if (proc != NULL) - { - memset(&proc_info, 0, sizeof(proc_info)); - while (readproc(proc, &proc_info) != NULL) - { - if (proc_info.cmd == input_pname) - { - if (0 == kill(proc_info.tid, SIGTERM)) - { - ret_value = true; - LOGINFO("Killed the process [%d] process name [%s]", proc_info.tid, proc_info.cmd); - } - } - } - closeproc(proc); - } - return ret_value; -} - -/** -* @brief Get list of child processes with the given parent process ID, equivalent to "pgrep -P " -* @param[in] input_ppid - The given parent process ID -* @param[out] processIds - The list of child process IDs -* @return true if there are any child processes of the given parent process ID, otherwise false is returned -*/ -bool getChildProcessIDs(int input_ppid, vector& processIds) -{ - PROCTAB* proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS); - proc_t proc_info = {0}; - bool ret_value = false; - - if (proc != NULL) - { - memset(&proc_info, 0, sizeof(proc_info)); - while (readproc(proc, &proc_info) != NULL) - { - if (proc_info.ppid == input_ppid) - { - processIds.push_back(proc_info.tid); - ret_value = true; - } - } - closeproc(proc); - } - return ret_value; -} - -} diff --git a/helpers/UtilsSearchRDKProfile.h b/helpers/UtilsSearchRDKProfile.h deleted file mode 100644 index ce4ddeb..0000000 --- a/helpers/UtilsSearchRDKProfile.h +++ /dev/null @@ -1,75 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ -#pragma once - -#include -#include -#include -#include -#include -using namespace std; - -#define RDK_PROFILE "RDK_PROFILE=" -#define PROFILE_TV "TV" -#define PROFILE_STB "STB" - -typedef enum profile { - NOT_FOUND = -1, - STB = 0, - TV, - MAX -} profile_t; - -profile_t profileType = NOT_FOUND; - -profile_t searchRdkProfile(void) { - - const char* devPropPath = "/etc/device.properties"; - char line[256], *rdkProfile = NULL; - profile_t ret = NOT_FOUND; - FILE* file; - - file = fopen(devPropPath, "r"); - if (file == NULL) { - printf("File not found issue \n"); - return NOT_FOUND; - } - - while (fgets(line, sizeof(line), file)) { - rdkProfile = strstr(line, RDK_PROFILE); - if (rdkProfile != NULL) { - rdkProfile += strlen(RDK_PROFILE); // Move past the 'RDK_PROFILE=' - printf("Found RDK_PROFILE: %s \n", rdkProfile); - break; - } - } - - if (rdkProfile != NULL) { - if (strncmp(rdkProfile, PROFILE_TV, strlen(PROFILE_TV)) == 0) { - ret = TV; - } else if (strncmp(rdkProfile, PROFILE_STB, strlen(PROFILE_STB)) == 0) { - ret = STB; - } - } else { - printf("Found RDK_PROFILE: NOT_FOUND \n"); - ret = NOT_FOUND; - } - fclose(file); - return ret; -} diff --git a/helpers/UtilsString.h b/helpers/UtilsString.h deleted file mode 100644 index 8091719..0000000 --- a/helpers/UtilsString.h +++ /dev/null @@ -1,228 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -namespace Utils { -namespace String { - // locale-wise comparison - template - struct loc_equal { - explicit loc_equal(const std::locale& loc) - : loc_(loc) - { - } - bool operator()(charT ch1, charT ch2) - { - return std::toupper(ch1, loc_) == std::toupper(ch2, loc_); - } - - private: - const std::locale& loc_; - }; - - // Case-insensitive substring lookup. - // Returns the substring position or -1 - // Example: int pos = find_substr_ci(string, substring, std::locale()); - template - int find_substr_ci(const T& string, const T& substring, const std::locale& loc = std::locale()) - { - typename T::const_iterator it = std::search(string.begin(), string.end(), - substring.begin(), substring.end(), loc_equal(loc)); - if (it != string.end()) - return it - string.begin(); - else - return -1; // not found - } - - // Case-insensitive substring inclusion lookup. - // Example: if (Utils::String::contains(result, processName)) {..} - template - bool contains(const T& string, const T& substring, const std::locale& loc = std::locale()) - { - int pos = find_substr_ci(string, substring, loc); - return pos != -1; - } - - // Case-insensitive substring inclusion lookup. - // Example: if(Utils::String::contains(tmp, "grep -i")) {..} - template - bool contains(const T& string, const char* c_substring, const std::locale& loc = std::locale()) - { - std::string substring(c_substring); - int pos = find_substr_ci(string, substring, loc); - return pos != -1; - } - - // Case-insensitive string comparison - // returns true if the strings are equal, otherwise returns false - // Example: if (Utils::String::equal(line, provisionType)) {..} - template - bool equal(const T& string, const T& string2, const std::locale& loc = std::locale()) - { - int pos = find_substr_ci(string, string2, loc); - bool res = (pos == 0) && (string.length() == string2.length()); - return res; - } - - // Case-insensitive string comparison - // returns true if the strings are equal, otherwise returns false - // Example: if(Utils::String::equal(line,"CRYPTANIUM")) {..} - template - bool equal(const T& string, const char* c_string2, const std::locale& loc = std::locale()) - { - std::string string2(c_string2); - int pos = find_substr_ci(string, string2, loc); - bool res = (pos == 0) && (string.length() == string2.length()); - return res; - } - - // Trim space characters (' ', '\n', '\v', '\f', \r') on the left side of string - inline void ltrim(std::string& s) - { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); - } - - // Trim space characters (' ', '\n', '\v', '\f', \r') on the right side of string - inline void rtrim(std::string& s) - { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), - s.end()); - } - - // Trim space characters (' ', '\n', '\v', '\f', \r') on both sides of string - inline void trim(std::string& s) - { - ltrim(s); - rtrim(s); - } - - inline void toUpper(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), ::toupper); - } - - inline void toLower(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), ::tolower); - } - - // case insensitive comparison of strings - inline bool stringContains(const std::string& s1, const std::string& s2) - { - return search(s1.begin(), s1.end(), s2.begin(), s2.end(), [](char c1, char c2) { return toupper(c1) == toupper(c2); }) != s1.end(); - } - - // case insensitive comparison of strings - inline bool stringContains(const std::string& s1, const char* s2) - { - return stringContains(s1, std::string(s2)); - } - - // Split string s into a vector of strings using the supplied delimiter - inline void split(std::vector &stringList, std::string &s, std::string delimiters) - { - size_t current; - size_t next = -1; - do - { - current = next + 1; - next = s.find_first_of( delimiters, current ); - - stringList.push_back(s.substr( current, next - current )); - } - while (next != string::npos); - } - - static const TCHAR base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - - inline void imageEncoder(const uint8_t object[], const uint32_t length, const bool padding, string& result) - { - uint8_t state = 0; - uint32_t index = 0; - uint8_t lastStuff = 0; - - while (index < length) { - if (state == 0) { - result += base64_chars[((object[index] & 0xFC) >> 2)]; - lastStuff = ((object[index] & 0x03) << 4); - state = 1; - } else if (state == 1) { - result += base64_chars[(((object[index] & 0xF0) >> 4) | lastStuff)]; - lastStuff = ((object[index] & 0x0F) << 2); - state = 2; - } else if (state == 2) { - result += base64_chars[(((object[index] & 0xC0) >> 6) | lastStuff)]; - result += base64_chars[(object[index] & 0x3F)]; - state = 0; - } - index++; - } - if (state != 0) { - result += base64_chars[lastStuff]; - - if (padding == true) { - if (state == 1) { - result += _T("=="); - } else { - result += _T("="); - } - } - } - - } - -/** -* @brief Remove extra spaces from the given input string -* @param[in] in_str - The input string -* @param[out] out_str - The output string (equals input_string with extra spaces removed) -* @return true if the input string is a valid string -*/ - inline bool removeExtraWhitespaces(string& in_str, string& out_str) - { - bool ret_status = false; - int idx = 0; - if (!in_str.empty()) - { - while (in_str[idx] != '\0') - { - out_str += in_str[idx]; - if (in_str[idx] == ' ') - { - while (in_str[idx+1] == ' ') - { - idx++; - } - } - idx++; - } - ret_status = true; - } - return ret_status; - } - -} -} diff --git a/helpers/UtilsSynchro.hpp b/helpers/UtilsSynchro.hpp deleted file mode 100644 index 0039fd2..0000000 --- a/helpers/UtilsSynchro.hpp +++ /dev/null @@ -1,117 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include "UtilsLogging.h" - -using namespace WPEFramework; - -namespace Utils { - namespace Synchro { - - namespace { - // set when inside of getFunctionToCall wrapper (or locked IARM handler - see UtilsSynchroIarm.hpp) - thread_local bool isThreadUsingLockedApi = false; - } - - // keeps API locks, one per specific class - template - struct ApiLocks { - static std::recursive_mutex mtx; - }; - - template std::recursive_mutex ApiLocks::mtx; - - template - std::function - getFunctionToCall(const std::string& debugname, const METHOD& method, REALOBJECT* objectPtr) { - return [debugname, method](REALOBJECT *obj, const WPEFramework::Core::JSON::VariantContainer& in, WPEFramework::Core::JSON::VariantContainer& out) -> uint32_t { - isThreadUsingLockedApi = true; - // printf("METHOD CALL, GETTING LOCK: REALOBJECT '%s', method: '%s' MUTEX:%p\n",typeid(REALOBJECT).name(), debugname.c_str(), &ApiLocks::mtx); fflush(stdout); - std::lock_guard lock(ApiLocks::mtx); - LOGINFO("calling %s with lock: %p\n", debugname.c_str(), &ApiLocks::mtx); - uint32_t ret; - try { - ret = (obj->*method)(in, out); - } catch (...) { - isThreadUsingLockedApi = false; - throw; - } - isThreadUsingLockedApi = false; - return ret; - }; - } - - template - void RegisterLockedApi(const string& methodName, const METHOD& method, REALOBJECT* objectPtr) - { - using MethodType = decltype(getFunctionToCall(methodName, method, objectPtr)); - objectPtr->PluginHost::JSONRPC::Register(methodName, getFunctionToCall(methodName, method, objectPtr), objectPtr); - } - - template - void RegisterLockedApiForVersions(const string& methodName, const METHOD& method, REALOBJECT* objectPtr, const std::vector versions) - { - objectPtr->PluginHost::JSONRPC::Register(methodName, getFunctionToCall(methodName, method, objectPtr), objectPtr, versions); - } - - template - void RegisterLockedApiForHandler(Core::JSONRPC::Handler* handler, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) - { - handler->Register(methodName, getFunctionToCall(methodName, method, objectPtr), objectPtr); - } - - /* - This guard can unlock & re-lock api mutex to prevent deadlock possible when calling other plugins via Invoke - (could deadlock in case when that other plugin called Invoke on this plugin at the same time, or tried to call - this plugin recursively, from the Invoke'd call). - */ - template - struct UnlockApiGuard { - UnlockApiGuard() { - if (isThreadUsingLockedApi) { - ApiLocks::mtx.unlock(); - } - } - ~UnlockApiGuard() { - if (isThreadUsingLockedApi) { - ApiLocks::mtx.lock(); - } - } - }; - - template - struct LockApiGuard { - std::unique_lock _lock; - LockApiGuard() : _lock(ApiLocks::mtx) {} - void unlock() { - _lock.unlock(); - } - void lock() { - _lock.lock(); - } - }; - - - } // Utils -} // Synchro \ No newline at end of file diff --git a/helpers/UtilsSynchroIarm.hpp b/helpers/UtilsSynchroIarm.hpp deleted file mode 100644 index 8e5a8df..0000000 --- a/helpers/UtilsSynchroIarm.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include -#include "UtilsLogging.h" - -using namespace WPEFramework; - -namespace Utils { - - namespace Synchro { - - // owner -> map( eventId -> real handler) - using HandlerMapType = std::map>; - - // maps evnt types to handlers, one per specific class - template - struct IarmHandlers { - static HandlerMapType _registered_iarm_handlers; - }; - - template - HandlerMapType IarmHandlers::_registered_iarm_handlers; - - // we need separate handler per class, so that when we call IARM_Bus_RemoveEventHandler, we will not - // remove _generic_iarm_handler registered by other classes/in-process plugins - template - static void _generic_iarm_handler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) { - auto& handlers_map = IarmHandlers::_registered_iarm_handlers; - isThreadUsingLockedApi = true; - std::lock_guard lock(ApiLocks::mtx); - LOGINFO("calling handler %s/%d with lock: %p\n", owner, eventId, &ApiLocks::mtx); - try { - handlers_map[owner][eventId](owner, eventId, data, len); - } catch (...) { - isThreadUsingLockedApi = false; - throw; - } - isThreadUsingLockedApi = false; - } - - template - static IARM_Result_t RegisterLockedIarmEventHandler(const char *ownerName, IARM_EventId_t eventId, IARM_EventHandler_t handler) { - auto generic_handler = _generic_iarm_handler; - auto& handlers_map = IarmHandlers::_registered_iarm_handlers; - - std::lock_guard lock(ApiLocks::mtx); - handlers_map[ownerName][eventId] = handler; - return ::IARM_Bus_RegisterEventHandler(ownerName, eventId, generic_handler); - } - - template - static IARM_Result_t RemoveLockedEventHandler(const char *ownerName, IARM_EventId_t eventId, IARM_EventHandler_t handler) { - auto& handlers_map = IarmHandlers::_registered_iarm_handlers; - - std::lock_guard lock(ApiLocks::mtx); - if (handler != handlers_map[ownerName][eventId]) { - LOGERR("class %s RemoveLockedEventHandler for ownerName: %s, event: %d passed handler: %p different than registered: %p\n", typeid(UsingClass).name(), ownerName, eventId, handler, handlers_map[ownerName][eventId]); fflush(stdout); - } - // still erase the event in any case - handlers_map[ownerName].erase(eventId); - return ::IARM_Bus_RemoveEventHandler(ownerName, eventId, _generic_iarm_handler); - } - } // Synchro -} // Utils diff --git a/helpers/UtilsThreadRAII.h b/helpers/UtilsThreadRAII.h deleted file mode 100644 index 995a066..0000000 --- a/helpers/UtilsThreadRAII.h +++ /dev/null @@ -1,55 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "UtilsLogging.h" - -namespace Utils { - -class ThreadRAII { -public: - ThreadRAII() {} - ThreadRAII(std::thread&& t) - : t(std::move(t)) - { - } - ~ThreadRAII() - { - try { - if (t.joinable()) { - t.join(); - } - } catch (const std::system_error& e) { - LOGERR("system_error exception in thread join %s", e.what()); - } catch (const std::exception& e) { - LOGERR("exception in thread join %s", e.what()); - } - } - - //support moving - ThreadRAII(ThreadRAII&&) = default; - ThreadRAII& operator=(ThreadRAII&&) = default; - - std::thread& get() { return t; } - -private: - std::thread t; -}; -} diff --git a/helpers/UtilsUUID.h b/helpers/UtilsUUID.h deleted file mode 100644 index 59d958d..0000000 --- a/helpers/UtilsUUID.h +++ /dev/null @@ -1,37 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include - -class UtilsUUID { - public: - static std::string GenerateUUID() { - uuid_t uuid; - char uuid_str[37]; - - uuid_generate(uuid); - uuid_unparse_lower(uuid, uuid_str); - uuid_clear(uuid); - - std::string traceId(uuid_str); - return traceId; - } -}; \ No newline at end of file diff --git a/helpers/UtilsUnused.h b/helpers/UtilsUnused.h deleted file mode 100644 index 786a6e8..0000000 --- a/helpers/UtilsUnused.h +++ /dev/null @@ -1,22 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#define UNUSED(expr)(void)(expr) diff --git a/helpers/UtilsfileExists.h b/helpers/UtilsfileExists.h deleted file mode 100644 index 6ddffb4..0000000 --- a/helpers/UtilsfileExists.h +++ /dev/null @@ -1,30 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include - -namespace Utils { -inline bool fileExists(const char* pFileName) -{ - struct stat fileStat; - return 0 == stat(pFileName, &fileStat); -} -} diff --git a/helpers/UtilsgetFileContent.h b/helpers/UtilsgetFileContent.h deleted file mode 100755 index 3668138..0000000 --- a/helpers/UtilsgetFileContent.h +++ /dev/null @@ -1,324 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include - -#include "UtilsString.h" -#define READ_BUFFER_SIZE 1024 -namespace Utils { - -/** - * @brief Read the property value from the given file based on the provided property name. - * @param[in] filename - The name of the file from which to read the properties. - * @param[in] property - The name of the property to search for in the file. - * @param[out] propertyValue - The value of the property will be stored in this string. - * @return bool True if the property is found and successfully read, false otherwise. - */ -inline bool readPropertyFromFile(const char* filename, const string& property, string& propertyValue) -{ - string line = ""; - bool found = false; - std::ifstream file(filename); - propertyValue = ""; - if (file.is_open()) - { - while (std::getline(file, line)) - { - // Skip lines that start with '#' (single-line comments) - if (!line.empty() && line[0] == '#') - { - continue; - } - if (line.find(property + " ") == 0 || line.find(property + "=") == 0) - { - string propertyContent = line.substr(line.find("=") + 1); - - // If the property value starts with '$',recursively expand it - if (!propertyContent.empty() && propertyContent[0] == '$') - { - string expandedProperty = propertyContent.substr(1); - if (readPropertyFromFile(filename, expandedProperty, propertyValue)) - { - found = true; - break; - } - else - { - LOGERR("Failed to find expanded property: %s", expandedProperty.c_str()); - } - } - else - { - // If it does not start with '$', set propertyValue directly - propertyValue = propertyContent; - if (!propertyValue.empty()) - { - // Remove new line character from end of the string if it exists - if ((propertyValue.back() == '\r') || (propertyValue.back() == '\n')) - { - propertyValue.pop_back(); - } - } - found = true; - break; - } - } - } - } - else - { - LOGERR("File is not open"); - } - - // If the property was not found, set the propertyValue to an empty string - if (!found) - { - LOGERR("Variable value is empty"); - } - - return found; -} - -/** - * @brief Read the content of a file and store it in the provided string. - * @param[in] filename - The name of the file to read. - * @param[out] content - The content of the file will be stored in this string. - * @return bool True if the file is successfully read and its content is stored in 'content', false otherwise. - */ -inline bool readFileContent(const char* filename, string& content) -{ - char buffer[READ_BUFFER_SIZE]; - FILE* file = fopen(filename, "r"); - bool found = false; - - if (file) - { - while (fgets(buffer, sizeof(buffer), file) != NULL) - { - content += buffer; - found = true; - } - fclose(file); - - } - else - { - LOGERR("Failed to open the file"); - } - - return found; -} - - -/** - * @brief Check if a given path corresponds to a regular file. - * @param[in] path - The path to check. - * @return bool - True if the path corresponds to a regular file, false otherwise. - */ -inline bool isRegularFile(const string& path) -{ - struct stat st; - if (stat(path.c_str(), &st) == 0) - { - return S_ISREG(st.st_mode); - } - return false; -} - - -inline bool searchFilesRec(std::vector &pathList, unsigned int currentDepth, const std::list& exclusions, string& result) -{ - int count = 0; - - if (pathList.size() == 0) - { - LOGERR("Empty path"); - return false; - } - - std::string inputPath = "/"; - for (unsigned int n = 0; n < currentDepth; n++) - { - inputPath += pathList[n]; - inputPath += "/"; - } - - std::string currentPath = pathList[currentDepth]; - - if (currentPath.find('*') != std::string::npos || currentPath.find('?') != std::string::npos) - { - // Process files and directories in the current directory - DIR *dir = opendir(inputPath.c_str()); - if (!dir) - { - LOGERR("Failed to open the directory '%s'", inputPath.c_str()); - return false; - } - - std::string pattern_s = currentPath; - size_t pos = 0; - while ((pos = pattern_s.find('*', pos)) != std::string::npos) - { - pattern_s.replace(pos, 1, "[^\\n]*"); - pos += 6; - } - - pos = 0; - while ((pos = pattern_s.find('?', pos)) != std::string::npos) - { - pattern_s.replace(pos, 1, "[^\\n]{1}"); - pos += 8; - } - - std::regex pattern(pattern_s.c_str()); - std::smatch matches; - - struct dirent *entry; - while ((entry = readdir(dir))) - { - string fileName = entry->d_name; - - if (fileName == "." || fileName == "..") - { - continue; - } - - if (std::regex_search(fileName, matches, pattern)) - { - if (std::find(exclusions.begin(), exclusions.end(), fileName) == exclusions.end()) - { - if (currentDepth >= pathList.size() - 1) - { - inputPath += fileName; - if (access(inputPath.c_str(), F_OK) == 0) - { - result += inputPath + "\n"; - - count++; - if (count >= 10) - break; // Stop when count reaches 10 - } - } - else - { - pathList[currentDepth] = fileName; - searchFilesRec(pathList, currentDepth + 1, exclusions, result); - } - } - } - } - closedir(dir); - } - else - { - if (currentDepth >= pathList.size() - 1 ) - { - inputPath += currentPath; - if (access(inputPath.c_str(), F_OK) == 0) - { - result += inputPath + "\n"; - return true; - } - } - else - { - searchFilesRec(pathList, currentDepth + 1, exclusions, result); - } - } - - return true; -} - -/** - * @brief Recursively search for files and directories in a given directory path, with depth limits and exclusions. - * @param[in] inputPath - The directory path to start the search from. - * @param[in] maxDepth - The maximum depth of subdirectories to search (0 for no limit). - * @param[in] minDepth - The minimum depth of subdirectories to start searching from (0 to start from inputPath). - * @param[in] exclusions - A list of paths to exclude from the search. - * @param[out] result - The search results will be stored in this string.Results are capped at 10. - * @return bool - True if the search operation is successful, false otherwise. - */ -inline bool searchFiles(string& inputPath, int maxDepth, int minDepth, const std::list& exclusions, string& result) -{ - std::vector pathList; - Utils::String::split(pathList, inputPath, "/"); - pathList.erase(pathList.begin(), pathList.begin() + 1); - - return searchFilesRec(pathList, 0, exclusions,result); -} - -/** - * @brief Process a string containing variables and replace them with corresponding values. - * - * @param[in] input - The input string containing variables; delimited by ' ' or '/' - * @param[in] filePath - The path to the file containing property values. - * @param[out] expandedString - The string with variables replaced by values. - * @return bool - True if the processing and replacement are successful, false otherwise. - */ -inline bool ExpandPropertiesInString(const char* input, const char* filePath, string & expandedString) -{ - const char* variablePos = strchr(input, '$'); - while (variablePos) - { - expandedString.assign(input, variablePos - input); - const char* endPos = strpbrk(variablePos, " /"); - if (endPos) - { - size_t variableLength = endPos - variablePos - 1; - char variable[variableLength + 1]; - strncpy(variable, variablePos + 1, variableLength); - variable[variableLength] = '\0'; - - string tempPropertyValue; - if (readPropertyFromFile(filePath, variable, tempPropertyValue)) - { - const char* propertyValue = tempPropertyValue.c_str(); - expandedString += tempPropertyValue; - variablePos += strlen(propertyValue); - } - else - { - LOGERR("Variable '%s' not found or error reading value.\n", variable); - return false; - } - } - - else - { - endPos = variablePos + 1; - } - variablePos = strchr(endPos, '$'); - if (variablePos) - { - expandedString.append(endPos, variablePos - endPos); - } - else - { - expandedString += endPos; - } - } - - return true; -} - -} diff --git a/helpers/UtilsgetRFCConfig.h b/helpers/UtilsgetRFCConfig.h deleted file mode 100644 index 769e0d5..0000000 --- a/helpers/UtilsgetRFCConfig.h +++ /dev/null @@ -1,33 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "rfcapi.h" - -namespace Utils { -inline bool getRFCConfig(const char* paramName, RFC_ParamData_t& paramOutput) -{ - WDMP_STATUS wdmpStatus = getRFCParameter(nullptr, paramName, ¶mOutput); - if (wdmpStatus == WDMP_SUCCESS || wdmpStatus == WDMP_ERR_DEFAULT_VALUE) { - return true; - } - return false; -} -} diff --git a/helpers/UtilsisValidInt.h b/helpers/UtilsisValidInt.h deleted file mode 100644 index c90ebbd..0000000 --- a/helpers/UtilsisValidInt.h +++ /dev/null @@ -1,70 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2024 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include - -namespace Utils { -inline bool isValidInt(char* x) -{ - bool Checked = true; - int i = 0; - - if (x[0] == '-') { - i = 1; - } - - do { - //valid digit? - if (isdigit(x[i])) { - //to the next character - i++; - Checked = true; - } else { - //to the next character - i++; - Checked = false; - break; - } - } while (x[i] != '\0'); - return Checked; -} - -inline bool isValidUnsignedInt(char* x) -{ - bool Checked = true; - int i = 0; - - do { - //valid digit? - if (isdigit(x[i])) { - //to the next character - i++; - Checked = true; - } else { - //to the next character - i++; - Checked = false; - break; - } - } while (x[i] != '\0'); - return Checked; -} -} diff --git a/helpers/WebSocketLink.h b/helpers/WebSocketLink.h deleted file mode 100644 index 8376b4e..0000000 --- a/helpers/WebSocketLink.h +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include "UtilsLogging.h" - -namespace WPEFramework { -namespace Web { - namespace WebSocket { - - template - class HWebSocketLinkType { - public: - enum EnumlinkState : uint8_t { - WEBSERVER = 0x01, - UPGRADING = 0x02, - WEBSOCKET = 0x04, - SUSPENDED = 0x08, - ACTIVITY = 0x10 - }; - - typedef HWebSocketLinkType ParentClass; - - private: - template - class HandlerType : public ACTUALLINK { - private: - typedef HandlerType ThisClass; - - class SerializerImpl : public OUTBOUND::Serializer { - private: - typedef typename OUTBOUND::Serializer BaseClass; - - SerializerImpl() = delete; - SerializerImpl(const SerializerImpl&) = delete; - SerializerImpl& operator=(const SerializerImpl&) = delete; - - public: - SerializerImpl(ThisClass& parent, const uint8_t queueSize) - : OUTBOUND::Serializer() - , _parent(parent) - , _adminLock() - , _queue(queueSize) - { - } - virtual ~SerializerImpl() = default; - - public: - bool IsIdle() const - { - return (_queue.Count() == 0); - } - bool Submit(const Core::ProxyType& element) - { - bool result = false; - - _adminLock.Lock(); - - _queue.Add(const_cast&>(element)); - - // See if we need to push the first one.. - if (_queue.Count() == 1) { - result = true; - OUTBOUND::Serializer::Submit(*element); - } - - _adminLock.Unlock(); - - return (result); - } - uint16_t Serialize(uint8_t stream[], const uint16_t maxLength) - { - return (OUTBOUND::Serializer::Serialize(stream, maxLength)); - } - void Flush() - { - _adminLock.Lock(); - - OUTBOUND::Serializer::Flush(); - - while (_queue.Count() > 0) { - Core::ProxyType element; - _queue.Remove(0, element); - - _adminLock.Unlock(); - - _parent.Serialized(element); - - _adminLock.Lock(); - } - - _adminLock.Unlock(); - } - - private: - virtual void Serialized(const typename OUTBOUND::BaseElement& element) - { - _adminLock.Lock(); - - ASSERT(&element == static_cast(&(*(_queue[0])))); - DEBUG_VARIABLE(element); - - Core::ProxyType realItem; - _queue.Remove(0, realItem); - - _adminLock.Unlock(); - - if (_parent._webSocketMessage == realItem) { - _parent.UpgradeCompleted(); - } else { - _parent.Serialized(Core::ProxyType(realItem)); - } - - _adminLock.Lock(); - - if ((_parent.IsSuspended() == false) && (_queue.Count() > 0)) { - OUTBOUND::Serializer::Submit(*(_queue[0])); - _adminLock.Unlock(); - - _parent.Trigger(); - } else { - _adminLock.Unlock(); - } - - // TRACE_L1("Released the ref object %s [%p]\n", typeid(typename OUTBOUND::BaseElement).name(), &static_cast(*realItem)); - } - - private: - ThisClass& _parent; - Core::CriticalSection _adminLock; - Core::ProxyList _queue; - }; - class DeserializerImpl : public INBOUND::Deserializer { - private: - DeserializerImpl() = delete; - DeserializerImpl(const DeserializerImpl&) = delete; - DeserializerImpl& operator=(const DeserializerImpl&) = delete; - - public: - DeserializerImpl(ThisClass& parent, const uint8_t queueSize) - : INBOUND::Deserializer() - , _parent(parent) - , _pool(queueSize) - { - } - DeserializerImpl(ThisClass& parent, ALLOCATOR allocator) - : INBOUND::Deserializer() - , _parent(parent) - , _pool(allocator) - { - } - virtual ~DeserializerImpl() = default; - - public: - bool IsIdle() const - { - return (_current.IsValid() == false); - } - virtual void Deserialized(typename INBOUND::BaseElement& element) - { - ASSERT(&element == static_cast(&(*(_current)))); - DEBUG_VARIABLE(element); - - _parent.Deserialized(_current); - - _current.Release(); - } - virtual typename INBOUND::BaseElement* Element() - { - if (_parent.IsSuspended() == false) { - _current = _pool.Element(); - - ASSERT(_current.IsValid()); - - return static_cast(&(*_current)); - } - - return (nullptr); - } - virtual bool LinkBody(typename INBOUND::BaseElement& element) - { - ASSERT(&element == static_cast(&(*(_current)))); - DEBUG_VARIABLE(element); - - return (_parent.LinkBody(_current)); - } - - private: - ThisClass& _parent; - Core::ProxyType _current; - ALLOCATOR _pool; - }; - - public: - HandlerType() = delete; - HandlerType(const HandlerType&) = delete; - HandlerType& operator=(const HandlerType&) = delete; - -PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST) - template - HandlerType(ParentClass& parent, const bool binary, const bool masking, const uint8_t queueSize, Args&&... args) - : ACTUALLINK(std::forward(args)...) - , _handler(binary, masking) - , _parent(parent) - , _adminLock() - , _state(WEBSERVER) - , _serializerImpl(*this, queueSize) - , _deserialiserImpl(*this, queueSize) - , _path() - , _protocol() - , _query() - , _origin() - , _webSocketMessage(Core::ProxyType::Create()) - , _pingFireTime(0) - { - } - template - HandlerType(ParentClass& parent, const bool binary, const bool masking, const uint8_t queueSize, ALLOCATOR allocator, Args&&... args) - : ACTUALLINK(std::forward(args)...) - , _handler(binary, masking) - , _parent(parent) - , _adminLock() - , _state(WEBSERVER) - , _serializerImpl(*this, queueSize) - , _deserialiserImpl(*this, allocator) - , _path() - , _protocol() - , _query() - , _origin() - , _webSocketMessage(Core::ProxyType::Create()) - , _pingFireTime(0) - { - } -POP_WARNING() - ~HandlerType() override = default; - - public: - bool IsOpen() const - { - return ((ACTUALLINK::IsOpen() == true) && ((State() & SUSPENDED) == 0)); - } - bool IsSuspended() const - { - return ((ACTUALLINK::IsSuspended() == true) || ((State() & SUSPENDED) != 0)); - } - bool IsClosed() const - { - return (ACTUALLINK::IsClosed() == true); - } - bool IsWebServer() const - { - return ((State() & WEBSERVER) != 0); - } - bool IsUpgrading() const - { - return ((State() & UPGRADING) != 0); - } - bool IsWebSocket() const - { - return ((State() & WEBSOCKET) != 0); - } - bool IsCompleted() const - { - return (_handler.ReceiveInProgress() == false); - } - const string& Path() const - { - return (_path); - } - const ProtocolsArray& Protocols() const - { - return (_protocol); - } - void Protocols(const ProtocolsArray& protocols) - { - _protocol = protocols; - } - const string& Query() const - { - return (_query); - } - const string& Origin() const - { - return (_origin); - } - void Binary(const bool binary) - { - _handler.Binary(binary); - } - bool Binary() const - { - return (_handler.Binary()); - } - void Masking(const bool masking) - { - _handler.Masking(masking); - } - void Ping() - { - _pingFireTime = Core::Time::Now().Ticks(); - - _adminLock.Lock(); - - _handler.Ping(); - - _adminLock.Unlock(); - - ACTUALLINK::Trigger(); - } - bool Masking() const - { - return (_handler.Masking()); - } - bool Upgrade(const string& protocol, const string& path) - { - string empty; - - return (UpgradeToWebSocket(protocol, path, empty, ACTUALLINK::LocalId(), TemplateIntToType::value>())); - } - bool Upgrade(const string& protocol, const string& path, const string& query, const string& origin) - { - return (UpgradeToWebSocket(protocol, path, query, origin, TemplateIntToType::value>())); - } - void AbortUpgrade(const Web::WebStatus status, const string& reason) - { - // Do not return SWITCH if you would like to abort !!!!! - ASSERT(status != Web::STATUS_SWITCH_PROTOCOL); - - _webSocketMessage->ErrorCode = status; - _webSocketMessage->Message = reason; - } - void Submit(const Core::ProxyType& element) - { - _adminLock.Lock(); - - if ((IsSuspended() == false) && (IsOpen() == true) && (_serializerImpl.Submit(element) == true)) { - - _adminLock.Unlock(); - - ACTUALLINK::Trigger(); - } else { - _adminLock.Unlock(); - } - } - uint32_t Close(const uint32_t waitTime) - { - uint32_t result = 0; - - _adminLock.Lock(); - - if (IsSuspended() == false) { - if ((State() & WEBSOCKET) != 0) { - // Send out a close message - // TODO: Creat a message we can SEND - } - - // Do not accept any new messages. - _state |= SUSPENDED; - } - - _adminLock.Unlock(); - - result = CheckForClose(waitTime); - - return (result); - } - - // Methods to extract and insert data into the socket buffers - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override - { - uint16_t result = 0; - - _adminLock.Lock(); - - _state |= ACTIVITY; - - if ((_state & WEBSOCKET) != 0) { - if (maxSendSize > 4) { - result = _parent.SendData(&(dataFrame[4]), (maxSendSize - 4)); - - result = _handler.Encoder(dataFrame, (maxSendSize - 4), result); - } - } else { - result = _serializerImpl.Serialize(dataFrame, maxSendSize); - } - - _adminLock.Unlock(); - - if (result == 0) { - CheckForClose(0); - } - - return (result); - } - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) override - { - uint16_t result = 0; - - _adminLock.Lock(); - - _state |= ACTIVITY; - - if ((_state & WEBSOCKET) != 0) { - bool tooSmall = false; - - // check for multiple messages if available... - while ((result < receivedSize) && (tooSmall == false)) { - uint16_t actualDataSize = receivedSize - result; - uint16_t headerSize = _handler.Decoder(const_cast(&dataFrame[result]), actualDataSize); - uint64_t payloadSizeInControlFrame; - - tooSmall = ((headerSize == 0) && (actualDataSize == 0)); - - if (tooSmall == false) { - if ((_handler.FrameType() & 0xF0) != 0) { - - TRACE_L1("Oops we received uncomprehensable data on the web socket 0x%X", _handler.FrameType()); - - // Oops we got an error, Change link state !! - // ACTUALLINK::Close(0); - - // Nothing we can do with this shit.. - result = receivedSize; - } else if ((_handler.FrameType() & 0x08) != 0) { - // Build the associated message with this.. - // _commandData += dataFrame - - // If the message is complete execute the required command.. - if (_handler.IsCompleteMessage() == true) { - // It a control frame, react with the proper action. - if (_handler.FrameType() == WebSocket::Protocol::PING) { - // Send a PONG - _handler.Pong(); - ACTUALLINK::Trigger(); - } else if (_handler.FrameType() == WebSocket::Protocol::CLOSE) { - // Send a close response - _handler.Close(); - ACTUALLINK::Trigger(); - } else if (_handler.FrameType() == WebSocket::Protocol::PONG) { - if (_pingFireTime != 0) { - TRACE_L1("Ping acknowledged by a pong in %d (uS)", static_cast(static_cast(Core::Time::Now().Ticks() - _pingFireTime))); - _pingFireTime = 0; - } else { - TRACE_L1("Pong received but no ping requested ??? [%d] ", __LINE__); - } - } else { - // Unknown control command, log an error. - TRACE_L1("WebSocket unknown command received (%d)", _handler.FrameType()); - } - - _commandData.clear(); - } - - payloadSizeInControlFrame = 0; - // skip payload bytes for control frames: - if (headerSize > 1) { - payloadSizeInControlFrame = dataFrame[result + 1] & 0x7F; - if (payloadSizeInControlFrame == 126) { - if (headerSize > 3) { - payloadSizeInControlFrame = ((dataFrame[result + 2] << 8) + dataFrame[result + 3]); - } else { - TRACE_L1("Header too small for 16-bit extended payload size"); - payloadSizeInControlFrame = 0; - } - } else if (payloadSizeInControlFrame == 127) { - if (headerSize > 9) { - payloadSizeInControlFrame = dataFrame[result + 9]; - for (int i = 8; i >= 2; i--) payloadSizeInControlFrame = (payloadSizeInControlFrame << 8) + dataFrame[result + i]; - } else { - TRACE_L1("Header too small for 64-bit jumbo payload size "); - payloadSizeInControlFrame = 0; - } - } - } - - result += static_cast(headerSize + payloadSizeInControlFrame); // actualDataSize - - } else { - _parent.ReceiveData(&(dataFrame[result + headerSize]), actualDataSize); - - result += (headerSize + actualDataSize); - } - } - } - } else { - result = _deserialiserImpl.Deserialize(dataFrame, receivedSize); - } - - _adminLock.Unlock(); - - if (result == 0) { - CheckForClose(0); - } - - return (result); - } - - // Signal a state change, Opened, Closed, Accepted or Error - void StateChange() override - { - _adminLock.Lock(); - - // If the connection is closed by peer 'during' socket write, cleanup response message - if (IsClosed() == true) { - _serializerImpl.Flush(); - } - - _parent.StateChange(); - - _adminLock.Unlock(); - } - - void ResetActivity() - { - Core::SafeSyncType lock(_adminLock); - - _state &= ~ACTIVITY; - } - - bool HasActivity() const - { - Core::SafeSyncType lock(_adminLock); - - return ((_state & ACTIVITY) != 0); - } - - void Lock() const { - _adminLock.Lock(); - } - - void Unlock() const { - _adminLock.Unlock(); - } - - private: - inline uint16_t State() const - { - return (_state.load(Core::memory_order::memory_order_relaxed)); - } - uint32_t CheckForClose(uint32_t waitTime) - { - uint32_t result = 0; - - if ((IsSuspended() == true) && (_serializerImpl.IsIdle() == true) && (_deserialiserImpl.IsIdle() == true) && (_parent.IsIdle() == true)) { - result = ACTUALLINK::Close(waitTime); - } else - while (waitTime > 0) { - uint32_t sleepTime = (waitTime > 100 ? 100 : waitTime); - - if (sleepTime > 0) { - SleepMs(sleepTime); - - if (waitTime != Core::infinite) { - // Sleep for 100 ms and try again - waitTime -= sleepTime; - } - } - if ((IsOpen() == false) || ((IsSuspended() == true) && (_serializerImpl.IsIdle() == true) && (_deserialiserImpl.IsIdle() == true) && (_parent.IsIdle() == true))) { - result = ACTUALLINK::Close(waitTime); - - waitTime = 0; - } - } - - return (result); - } - void Serialized(const Core::ProxyType& element) - { - _parent.Send(Core::ProxyType(element)); - } - void Deserialized(Core::ProxyType& element) - { - ReceivedWebSocket(element, TemplateIntToType::value>()); - } - bool LinkBody(Core::ProxyType& element) - { - _parent.LinkBody(element); - - return (element->HasBody()); - } - void UpgradeCompleted() - { - UpgradeCompleted(TemplateIntToType::value>()); - } - - // ---------------------------------------------------------------------------------------------- - // SERVER upgrade to WebSocket, Diffrentiation via compiletime type: const TemplateIntToType<1>& - // ---------------------------------------------------------------------------------------------- - bool UpgradeToWebSocket(const string& /* protocol */, const string& /* path */, const string& /* query */, const string& /* origin */, const TemplateIntToType<1>& /* For compile time diffrentiation */) - { - // Servers can not upgrade to websockets - ASSERT(false); - - return (false); - } - void ReceivedWebSocket(Core::ProxyType& element, const TemplateIntToType<1>& /* For compile time diffrentiation */) - { - // we are still in the accepting mode - if ((element->Upgrade.IsSet()) && (element->Upgrade.Value() == Request::UPGRADE_WEBSOCKET) && (element->Connection.IsSet()) && (element->Connection.Value() == Request::CONNECTION_UPGRADE)) { - // Multiple message might be coming in, protect the state before we make assumptions on it value. - _adminLock.Lock(); - - if ((_state & WEBSERVER) == 0) { - _webSocketMessage->ErrorCode = Web::STATUS_INTERNAL_SERVER_ERROR; - _webSocketMessage->Message = _T("State of the link can not be upgraded."); - } else { - _state = static_cast((_state & 0xF0) | UPGRADING); - _protocol = element->WebSocketProtocol.Value(); - _path = element->Path; - LOGINFO("Is Query set: %d, %s", element->Query.IsSet(), element->Query.Value().c_str()); - if (element->Query.IsSet() == true) { - _query = element->Query.Value(); - } else { - _query.clear(); - } - - _webSocketMessage->Message.clear(); - _webSocketMessage->ErrorCode = Web::STATUS_SWITCH_PROTOCOL; - - _parent.StateChange(); - - if (_webSocketMessage->ErrorCode != Web::STATUS_SWITCH_PROTOCOL) { - _state = (_state & 0xF0) | WEBSERVER; - _path.clear(); - LOGINFO("Cleared query"); - _query.clear(); - _protocol.Clear(); - } else { - _webSocketMessage->Connection = Web::Response::CONNECTION_UPGRADE; - _webSocketMessage->Upgrade = Web::Response::UPGRADE_WEBSOCKET; - _webSocketMessage->WebSocketAccept = _handler.ResponseKey(element->WebSocketKey.Value()); - if (_protocol.Empty() == false) { - //only one protocol should be selected - ASSERT(_protocol.Size() == 1); - _webSocketMessage->WebSocketProtocol = _protocol.First(); - } - } - } - - // Send out the result of the upgraded message. - _serializerImpl.Submit(_webSocketMessage); - - _adminLock.Unlock(); - - ACTUALLINK::Trigger(); - } else { - _parent.Received(element); - } - } - void UpgradeCompleted(const TemplateIntToType<1>& /* For compile time diffrentiation */) - { - // We send back the response on what we upgraded, Assuming it was succesfull, we are upgraded. - if (_webSocketMessage->ErrorCode == Web::STATUS_SWITCH_PROTOCOL) { - ASSERT((_state & UPGRADING) != 0); - - _adminLock.Lock(); - - _state = (_state & 0xF0) | WEBSOCKET; - - _parent.StateChange(); - - _adminLock.Unlock(); - } - } - - // ---------------------------------------------------------------------------------------------- - // CLIENT upgrade to WebSocket, Diffrentiation via compiletime type: const TemplateIntToType<0>& - // ---------------------------------------------------------------------------------------------- - bool UpgradeToWebSocket(const string& protocol, const string& path, const string& query, const string& origin, const TemplateIntToType<0>& /* For compile time diffrentiation */) - { - bool result = false; - - _adminLock.Lock(); - - if ((_state & WEBSERVER) != 0) { - result = true; - _state = (_state & 0xF0) | UPGRADING; - _origin = (origin.empty() ? ACTUALLINK::LocalId() : origin); - - _webSocketMessage->Verb = Web::Request::HTTP_GET; - - _webSocketMessage->Origin = (origin.empty() ? ACTUALLINK::LocalId() : origin); - _webSocketMessage->Connection = Web::Request::CONNECTION_UPGRADE; - _webSocketMessage->Upgrade = Web::Request::UPGRADE_WEBSOCKET; - _webSocketMessage->WebSocketVersion = 13; - _webSocketMessage->Host = ACTUALLINK::RemoteId(); - _webSocketMessage->WebSocketKey = _handler.RequestKey(); - - if (path.empty() == false) { - _webSocketMessage->Path = path; - } - if (query.empty() == false) { - _webSocketMessage->Query = query; - } - if (protocol.empty() == false) { - _webSocketMessage->WebSocketProtocol = Web::ProtocolsArray(protocol); - } - _query = query; - LOGINFO("Query: %s", query.c_str()); - _path = path; - _protocol = Web::ProtocolsArray(protocol); - - _serializerImpl.Submit(_webSocketMessage); - ACTUALLINK::Trigger(); - } - - _adminLock.Unlock(); - - return (result); - } - void UpgradeCompleted(const TemplateIntToType<0>& /* For compile time diffrentiation */) - { - // We send out the request to upgrade. So what wait for the answer... - } - void ReceivedWebSocket(Core::ProxyType& element, const TemplateIntToType<0>& /* For compile time diffrentiation */) - { - // We might receive a response on the update request - if ((_webSocketMessage.IsValid() == true) && (element->ErrorCode == Web::STATUS_SWITCH_PROTOCOL) && (element->WebSocketAccept.Value() == _handler.ResponseKey(_webSocketMessage->WebSocketKey.Value()))) { - ASSERT((_state & UPGRADING) != 0); - - _adminLock.Lock(); - - // Seems like we succeeded, turn on the link.. - _state = (_state & 0xF0) | WEBSOCKET; - - _parent.StateChange(); - - _adminLock.Unlock(); - - ACTUALLINK::Trigger(); - } else if ((_webSocketMessage.IsValid() == true) && (element->ErrorCode == Web::STATUS_FORBIDDEN)) { - ASSERT((_state & UPGRADING) != 0); - - // Not allowed websocket - Close(0); - } else { - _parent.Received(element); - } - } - - private: - WebSocket::Protocol _handler; - ParentClass& _parent; - mutable Core::CriticalSection _adminLock; - std::atomic _state; - SerializerImpl _serializerImpl; - DeserializerImpl _deserialiserImpl; - string _path; - ProtocolsArray _protocol; - string _query; - string _origin; - string _commandData; - Core::ProxyType _webSocketMessage; - uint64_t _pingFireTime; - }; - - public: - HWebSocketLinkType() = delete; - HWebSocketLinkType(const HWebSocketLinkType& copy) = delete; - HWebSocketLinkType& operator=(const HWebSocketLinkType& RHS) = delete; - -PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST) - template - HWebSocketLinkType(const bool binary, const bool masking, const uint8_t queueSize, Args&&... args) - : _channel(*this, binary, masking, queueSize, std::forward(args)...) - { - } - template - HWebSocketLinkType(const bool binary, const bool masking, const uint8_t queueSize, ALLOCATOR allocator, Args&&... args) - : _channel(*this, binary, masking, queueSize, allocator, std::forward(args)...) - { - } -POP_WARNING() - virtual ~HWebSocketLinkType() = default; - - public: - LINK& Link() - { - return (_channel); - } - const LINK& Link() const - { - return (_channel); - } - string RemoteId() const - { - return (_channel.RemoteId()); - } - string LocalId() const - { - return (_channel.LocalId()); - } - bool IsOpen() const - { - return (_channel.IsOpen()); - } - bool IsSuspended() const - { - return (_channel.IsSuspended()); - } - bool IsClosed() const - { - return (_channel.IsClosed()); - } - bool IsWebServer() const - { - return (_channel.IsWebServer()); - } - bool IsUpgrading() const - { - return (_channel.IsUpgrading()); - } - bool IsWebSocket() const - { - return (_channel.IsWebSocket()); - } - bool IsCompleted() const - { - return (_channel.IsCompleted()); - } - void Binary(const bool binary) - { - _channel.Binary(binary); - } - bool Binary() const - { - return (_channel.Binary()); - } - void Masking(const bool masking) - { - _channel.Masking(masking); - } - bool Masking() const - { - return (_channel.Masking()); - } - void ResetActivity() - { - return (_channel.ResetActivity()); - } - bool HasActivity() const - { - return (_channel.HasActivity()); - } - const string& Path() const - { - return (_channel.Path()); - } - const string& Query() const - { - return (_channel.Query()); - } - const ProtocolsArray& Protocols() const - { - return (_channel.Protocols()); - } - void Protocols(const ProtocolsArray& protocols) - { - _channel.Protocols(protocols); - } - bool Upgrade(const string& protocol, const string& path, const string& query, const string& origin) - { - return (_channel.Upgrade(protocol, path, query, origin)); - } - void AbortUpgrade(const Web::WebStatus status, const string& reason) - { - return (_channel.AbortUpgrade(status, reason)); - } - uint32_t Open(const uint32_t waitTime) - { - LOGDBG("Opening Websocket TCP Binding"); - return (_channel.Open(waitTime)); - } - uint32_t Close(const uint32_t waitTime) - { - return (_channel.Close(waitTime)); - } - void Ping() - { - _channel.Ping(); - } - void Trigger() - { - _channel.Trigger(); - } - void Flush() - { - _channel.Flush(); - } - void Submit(Core::ProxyType element) - { - _channel.Submit(element); - } - - virtual void LinkBody(Core::ProxyType& element) = 0; - virtual void Received(Core::ProxyType& element) = 0; - virtual void Send(const Core::ProxyType& element) = 0; - virtual uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) = 0; - virtual uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) = 0; - virtual void StateChange() = 0; - virtual bool IsIdle() const = 0; - - protected: - void Lock() const { - _channel.Lock(); - } - void Unlock() const { - _channel.Unlock(); - } - - private: - HandlerType _channel; - }; - - template - class HWebSocketServerType { - private: - typedef HWebSocketServerType ThisClass; - - template - class Handler : public HWebSocketLinkType { - private: - typedef HWebSocketLinkType BaseClass; - - public: - Handler() = delete; - Handler(const Handler& copy) = delete; - Handler& operator=(const Handler& RHS) = delete; - - template - Handler(ThisClass& parent, const bool binary, const bool masking, Args&&... args) - : BaseClass(binary, masking, 1, WebSocket::RequestAllocator::Instance(), std::forward(args)...) - , _parent(parent) - { - } - ~Handler() override = default; - - public: - uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) override - { - return (_parent.SendData(dataFrame, maxSendSize)); - } - uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) override - { - return (_parent.ReceiveData(dataFrame, receivedSize)); - } - - private: - bool IsIdle() const override - { - return (_parent.IsIdle()); - } - // Signal a state change, Opened, Closed or Accepted - void StateChange() override - { - _parent.StateChange(); - } - void Received(Core::ProxyType& text) override - { - // This is a pure WebSocket, no web responses !!!! - TRACE_L1("Received a request(full) on a Websocket (%d)", 0); - } - void Send(const Core::ProxyType& text) override - { - // This is a pure WebSocket, no web responses !!!! - ASSERT(false); - } - void LinkBody(Core::ProxyType& element) override - { - // This is a pure WebSocket, no web requests !!!! - TRACE_L1("Received a request(body) on a Websocket (%d)", 0); - } - - private: - ThisClass& _parent; - }; - - public: - HWebSocketServerType() = delete; - HWebSocketServerType(const HWebSocketServerType& copy) = delete; - HWebSocketServerType& operator=(const HWebSocketServerType& RHS) = delete; - - template - HWebSocketServerType(const bool binary, const bool masking, Args&&... args) - : _channel(*this, binary, masking, std::forward(args)...) - { - } - virtual ~HWebSocketServerType() = default; - - public: - LINK& Link() - { - return (_channel.Link()); - } - const LINK& Link() const - { - return (_channel.Link()); - } - bool IsOpen() const - { - return (_channel.IsOpen() && _channel.IsWebSocket()); - } - bool IsClosed() const - { - return (_channel.IsClosed()); - } - bool IsWebServer() const - { - return (_channel.IsWebServer()); - } - bool IsWebSocket() const - { - return (_channel.IsWebSocket()); - } - bool IsUpgrading() const - { - return (_channel.IsUpgrading()); - } - bool IsSuspended() const - { - return (_channel.IsSuspended()); - } - bool IsCompleted() const - { - return (_channel.IsCompleted()); - } - void Binary(const bool binary) - { - _channel.Binary(binary); - } - bool Binary() const - { - return (_channel.Binary()); - } - void Masking(const bool masking) - { - _channel.Masking(masking); - } - bool Masking() const - { - return (_channel.Masking()); - } - uint32_t Open(const uint32_t waitTime) - { - LOGDBG("Opening the channel"); - return (_channel.Open(waitTime)); - } - uint32_t Close(const uint32_t waitTime) - { - return (_channel.Close(waitTime)); - } - - const string& Query() const - { - return (_channel.Query()); - } - void Trigger() - { - _channel.Trigger(); - } - string LocalId() const - { - return (_channel.LocalId()); - } - void Ping() - { - _channel.Ping(); - } - - virtual bool IsIdle() const = 0; - virtual void StateChange() = 0; - virtual uint16_t SendData(uint8_t* dataFrame, const uint16_t maxSendSize) = 0; - virtual uint16_t ReceiveData(uint8_t* dataFrame, const uint16_t receivedSize) = 0; - - private: - Handler _channel; - }; -} -} -} // namespace WPEFramework.Web diff --git a/helpers/WebSockets/CommunicationInterface/BinaryInterface.h b/helpers/WebSockets/CommunicationInterface/BinaryInterface.h deleted file mode 100644 index d93be55..0000000 --- a/helpers/WebSockets/CommunicationInterface/BinaryInterface.h +++ /dev/null @@ -1,59 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class BinaryInterface -{ -public: - BinaryInterface() = default; - - bool sendMessage(const std::string& message) - { - Derived& derived = static_cast(*this); - return derived.send(message); - } - - void setOnMessageHandler(const std::function& handler) - { - LOGINFO("Setting onMessage handler."); - onMessage = handler; - } - -protected: - ~BinaryInterface() = default; - - std::function onMessage{[](const std::string& message) { LOGWARN("Default onMessage."); }}; - websocketpp::frame::opcode::value opcode_{websocketpp::frame::opcode::binary}; - -private: - BinaryInterface(const BinaryInterface&) = delete; - BinaryInterface& operator=(const BinaryInterface&) = delete; -}; - -} // namespace WebSockets diff --git a/helpers/WebSockets/CommunicationInterface/CommandInterface.h b/helpers/WebSockets/CommunicationInterface/CommandInterface.h deleted file mode 100644 index b5082c3..0000000 --- a/helpers/WebSockets/CommunicationInterface/CommandInterface.h +++ /dev/null @@ -1,76 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include -#include -#include -#include - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class CommandInterface -{ -public: - CommandInterface() = default; - - bool sendCommand(std::string command, std::string& response) - { - LOGINFO("Send command: %s", command.c_str()); - Derived& derived = static_cast(*this); - if (derived.send(command)) - { - std::unique_lock lock(responseMutex_); - responseCondition_.wait_for(lock, std::chrono::seconds(5)); - response = lastResponse_; - return true; - } - - return false; - } - -protected: - ~CommandInterface() = default; - - void onMessage(const std::string& message) - { - LOGINFO("On message: %s", message.c_str()); - std::lock_guard lock(responseMutex_); - lastResponse_ = message; - responseCondition_.notify_one(); - } - - websocketpp::frame::opcode::value opcode_{websocketpp::frame::opcode::text}; - -private: - CommandInterface(const CommandInterface&) = delete; - CommandInterface& operator=(const CommandInterface&) = delete; - - std::string lastResponse_; - std::mutex responseMutex_; - std::condition_variable responseCondition_; -}; - -} // namespace WebSockets diff --git a/helpers/WebSockets/CommunicationInterface/JsonRpcInterface.h b/helpers/WebSockets/CommunicationInterface/JsonRpcInterface.h deleted file mode 100644 index 68d01b3..0000000 --- a/helpers/WebSockets/CommunicationInterface/JsonRpcInterface.h +++ /dev/null @@ -1,266 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#include "../JsonRpc/Request.h" -#include "../JsonRpc/Response.h" -#include "../JsonRpc/Notification.h" - -#include "Module.h" -#include "UtilsJsonRpc.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class JsonRpcInterface -{ -public: - JsonRpcInterface() = default; - - // Note: return value: sending result && receiving result && json-rpc's response field "success" value - bool sendRequest(const JsonRpc::Request& request, JsonRpc::Response& response); - void setNotificationHandler(std::function notificationHandler); - -protected: - ~JsonRpcInterface() = default; - void onMessage(const std::string& message); - - websocketpp::frame::opcode::value opcode_{websocketpp::frame::opcode::text}; - -private: - JsonRpcInterface(const JsonRpcInterface&) = delete; - JsonRpcInterface& operator=(const JsonRpcInterface&) = delete; - - bool getAsyncResponse(uint32_t id, std::future& futureReponse, JsonRpc::Response& response); - boost::optional > createFutureResponse(uint32_t id); - void removePromise(uint32_t id); - bool isRequestProcessingOngoing(uint32_t id); - void handleNotification(const std::string& message); - void handleResponse(uint32_t id, const std::string& message); - bool processResponse(uint32_t id, const std::string &responseString, JsonRpc::Response &deviceResponse) const; - - std::mutex responseMutex_; - std::map > responseToPromise_; - std::function notificationHandler_; -}; - -template -bool JsonRpcInterface::sendRequest(const JsonRpc::Request& request, JsonRpc::Response& response) -{ - if (isRequestProcessingOngoing(request.getId())) - { - LOGERR("Processing of request with ID:%d is already ongoing. Dropping new one:%s", - request.getId(), request.toString().c_str()); - return false; - } - - auto futureReponse = createFutureResponse(request.getId()); - if (!futureReponse) - { - LOGERR("Can't create future response."); - return false; - } - - LOGINFO("Sending json-rpc request: %s", request.toString().c_str()); - Derived& derived = static_cast(*this); - if (derived.send(request.toString())) - { - // Using futureResponse in addition to request.getId() to not lock mutex and search again. - return getAsyncResponse(request.getId(), *futureReponse, response); - } - else - { - LOGERR("Sending request with ID:%d failed. Cleaning internal state.", request.getId()); - removePromise(request.getId()); - return false; - } - return false; -} - -template -void JsonRpcInterface::setNotificationHandler(std::function notificationHandler) -{ - notificationHandler_ = notificationHandler; -} - -template -void JsonRpcInterface::onMessage(const std::string& message) -{ - LOGINFO("On message: %s", message.c_str()); - - JsonObject json; - if (!json.FromString(message)) - { - LOGERR("Discarding message. Message contains malformed JSON: %s", message.c_str()); - return; - } - if (json.HasLabel("id")) - { - LOGINFO("Message contains id field"); - if (json.HasLabel("method")) - { - // TO DO: Implement when there will be use case for client receiving request - // or when JsonRpcInterace will be used for SingleClientServer - } - else - { - if (json["id"].Content() != WPEFramework::Core::JSON::Variant::type::NUMBER) - { - LOGERR("Received message contains ID field which is not a number. Dropping."); - return; - } - handleResponse(json["id"].Number(), message); - return; - } - } - else - { - LOGINFO("Message doesn't contains id field"); - handleNotification(message); - } -} - -template -bool JsonRpcInterface::getAsyncResponse(uint32_t id, std::future& futureReponse, JsonRpc::Response& response) -{ - switch (futureReponse.wait_for(std::chrono::seconds(5))) - { - case std::future_status::ready: - removePromise(id); - return processResponse(id, futureReponse.get(), response); - case std::future_status::timeout: - LOGERR("Timeout for request/response ID:%d", id); - removePromise(id); - return false; - case std::future_status::deferred: - LOGERR("Execution for request/response ID:%d deferred. Internal error.", id); // "should not happen" - removePromise(id); - return false; - } - return false; -} - -template -boost::optional > JsonRpcInterface::createFutureResponse(uint32_t id) -{ - std::lock_guard lock(responseMutex_); - auto insertionResult = responseToPromise_.emplace(std::make_pair(id, std::promise{} )); - if (!insertionResult.second) - { - LOGERR("Request with the same ID:%d already saved.", id); - return boost::none; - } - return insertionResult.first->second.get_future(); -} - -template -void JsonRpcInterface::removePromise(uint32_t id) -{ - std::lock_guard lock(responseMutex_); - responseToPromise_.erase(id); -} - -template -bool JsonRpcInterface::isRequestProcessingOngoing(uint32_t id) -{ - std::lock_guard lock(responseMutex_); - return responseToPromise_.count(id) != 0; -} - -template -void JsonRpcInterface::handleNotification(const std::string& message) -{ - LOGINFO(); - JsonRpc::Notification notif; - notif.FromString(message); - if (!notif.isValid()) - { - LOGERR("Malformed jsonrpc notification. Dropping."); - return; - } - if (!notificationHandler_) - { - LOGINFO("No handler for notifications set. Dropping notification."); - return; - } - notificationHandler_(notif); -} - -template -void JsonRpcInterface::handleResponse(uint32_t id, const std::string& message) -{ - std::lock_guard lock(responseMutex_); - const auto& idToPromise = responseToPromise_.find(id); - if (idToPromise == responseToPromise_.end()) - { - LOGERR("Can't find request with id:%d. Dropping response.", id); - return; - }; - idToPromise->second.set_value(message); -} - -template -bool JsonRpcInterface::processResponse(uint32_t id, const std::string &responseString, JsonRpc::Response &deviceResponse) const -{ - bool success = false; - - deviceResponse.FromString(responseString); - - if (deviceResponse.isValid() && (deviceResponse.getId() == id)) - { - JsonObject parameters; - - if (deviceResponse.isResult()) - { - deviceResponse.getResult(parameters); - if (parameters.HasLabel("success")) - { - getBoolParameter("success", success); - LOGINFO("Result success: %u", success); - } - } - - if (deviceResponse.isError()) - { - deviceResponse.getError(parameters); - int error; - std::string message; - getNumberParameter("code", error); - getStringParameter("message", message); - LOGERR("Error code:message: %i:%s", error, message.c_str()); - } - } - else - { - LOGERR("Invalid response request_id:response_id %u:%u", id, deviceResponse.getId()); - } - - return success; -} - -} // namespace WebSockets diff --git a/helpers/WebSockets/ConnectionInitializationResult.h b/helpers/WebSockets/ConnectionInitializationResult.h deleted file mode 100644 index 65699ac..0000000 --- a/helpers/WebSockets/ConnectionInitializationResult.h +++ /dev/null @@ -1,54 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include - -namespace WebSockets { - -class ConnectionInitializationResult -{ -public: - ConnectionInitializationResult(bool success) : - success_(success), - authenticationSuccess_(true) - { - } - - operator bool() const - { - return success_; - } - - bool authenticationSuccess() const - { - return authenticationSuccess_; - } - - void setAuthenticationSuccess(bool authenticationSuccess) - { - authenticationSuccess_ = authenticationSuccess; - } - -private: - bool success_; - bool authenticationSuccess_; -}; - -} // namespace WebSockets diff --git a/helpers/WebSockets/Encryption/NoEncryption.h b/helpers/WebSockets/Encryption/NoEncryption.h deleted file mode 100644 index b7f641f..0000000 --- a/helpers/WebSockets/Encryption/NoEncryption.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include - -#include "websocketpp/config/asio_no_tls_client.hpp" -#include "websocketpp/client.hpp" - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class NoEncryption -{ -public: - NoEncryption() - { - LOGINFO("Creating not encrypted websocket.\n"); - } - -protected: - using EndpointType = typename Role::NotEncryptedEndpointType; - - ~NoEncryption() - { - LOGINFO("Destroying not encrypted websocket.\n"); - } - void setup() - { - LOGINFO("Encryption will not be set for this connection.\n"); - } - std::string addProtocolToAddress(const std::string& address) - { - return std::string("ws://") + address; - } - - void setAuthenticationState(ConnectionInitializationResult& result, websocketpp::connection_hdl handler) - { - result.setAuthenticationSuccess(true); - } -}; - -} // namespace WebSockets diff --git a/helpers/WebSockets/Encryption/TlsEnabled.h b/helpers/WebSockets/Encryption/TlsEnabled.h deleted file mode 100644 index 135190e..0000000 --- a/helpers/WebSockets/Encryption/TlsEnabled.h +++ /dev/null @@ -1,228 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include - -#include "websocketpp/config/asio_client.hpp" -#include "websocketpp/client.hpp" - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class TlsEnabled -{ -public: - TlsEnabled(); - void setCertFileName(const std::string& certFileName); - void setKeyFileName(const std::string& keyFileName); - void setCAFileNames(const std::vector& CAFileNames); - -protected: - using EndpointType = typename Role::EncryptedEndpointType; - using WebsocketppContextPtr = websocketpp::lib::shared_ptr; - - ~TlsEnabled(); - void setup(); - std::string addProtocolToAddress(const std::string& address); - void setAuthenticationState(ConnectionInitializationResult& result, websocketpp::connection_hdl hdl); - -private: - WebsocketppContextPtr onTlsInit(websocketpp::connection_hdl); - bool logIfCertFailure(bool preverified, boost::asio::ssl::verify_context& verify_ctx) const; - void loadCertificateAuthorities(const WebsocketppContextPtr& ctx) const; - - std::vector CAFileNames_; - std::string certFileName_; - std::string keyFileName_; -}; - -template -TlsEnabled::TlsEnabled() -{ - LOGINFO("Creating TLS enabled websocket."); -} - -template -void TlsEnabled::setCertFileName(const std::string& certFileName) -{ - LOGINFO("Setting cert file name to: %s", certFileName.c_str()); - certFileName_ = certFileName; -} - -template -void TlsEnabled::setKeyFileName(const std::string& keyFileName) -{ - LOGINFO("Setting key file name to: %s", keyFileName.c_str()); - keyFileName_ = keyFileName; -} - -template -void TlsEnabled::setCAFileNames(const std::vector& CAFileNames) -{ - LOGINFO("Setting CA files names with %i files.", CAFileNames.size()); - CAFileNames_ = CAFileNames; -} - -template -TlsEnabled::~TlsEnabled() -{ - LOGINFO("Destroying TLS enabled websocket."); -} - -template -void TlsEnabled::setup() -{ - LOGINFO("Setting up TLS handler."); - Derived& derived = static_cast(*this); - derived.endpointImpl_.set_tls_init_handler(std::bind(&TlsEnabled::onTlsInit, this, std::placeholders::_1)); -} - -template -std::string TlsEnabled::addProtocolToAddress(const std::string& address) -{ - return std::string("wss://") + address; -} - -template -void TlsEnabled::setAuthenticationState(ConnectionInitializationResult& result, websocketpp::connection_hdl handler) -{ - Derived& derived = static_cast(*this); - const auto& connection = derived.getConnection(handler); - - const auto& errorCategory = websocketpp::transport::asio::socket::get_socket_category(); - if (errorCategory == connection->get_ec().category()) - { - using namespace websocketpp::transport::asio::socket; - switch (connection->get_ec().value()) - { - case error::value::security: - case error::value::invalid_tls_context: - case error::value::tls_handshake_timeout: - case error::value::missing_tls_init_handler: - case error::value::tls_handshake_failed: - case error::value::tls_failed_sni_hostname: - LOGINFO("TLS connection not established."); - result.setAuthenticationSuccess(false); - return; - break; - default: - break; - } - } - result.setAuthenticationSuccess(true); -} - -template -typename TlsEnabled::WebsocketppContextPtr TlsEnabled::onTlsInit(websocketpp::connection_hdl) -{ - LOGINFO("Establishing TLS context."); - WebsocketppContextPtr ctx = std::make_shared(boost::asio::ssl::context::sslv23); - - try { - LOGINFO("Setting support for TLS1.2 only."); - ctx->set_options(boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::no_sslv3 | - boost::asio::ssl::context::no_tlsv1 | - boost::asio::ssl::context::no_tlsv1_1 | - boost::asio::ssl::context::single_dh_use); - - LOGINFO("Setting verify mode to verify peer."); - ctx->set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); - ctx->set_verify_callback( - std::bind(&TlsEnabled::logIfCertFailure, this, std::placeholders::_1, std::placeholders::_2)); - - loadCertificateAuthorities(ctx); - - LOGINFO("Enabling advanced cipher negotiation."); - SSL_CTX_set_ecdh_auto(ctx->native_handle(), 1); - - LOGINFO("Loading certificates to context."); - if (!boost::filesystem::exists(certFileName_)) - { - LOGWARN("Cert file not found."); - return ctx; - } - LOGINFO("Loading certificate chain from: %s", certFileName_.c_str()); - ctx->use_certificate_chain_file(certFileName_); - - if (!boost::filesystem::exists(keyFileName_)) - { - LOGERR("Key file not found."); - return ctx; - } - LOGINFO("Loading private key from: %s", keyFileName_.c_str()); - ctx->use_private_key_file(keyFileName_, boost::asio::ssl::context::pem); - - } catch (const std::exception& e) { - LOGERR("Error in context pointer: %s", e.what()); - } - - return ctx; -}; - -template -bool TlsEnabled::logIfCertFailure(bool preverified, boost::asio::ssl::verify_context& verify_ctx) const -{ - if (!preverified) - { - std::string errstr(X509_verify_cert_error_string(X509_STORE_CTX_get_error(verify_ctx.native_handle()))); - LOGERR("Certificate verification failed: %s", errstr.c_str()); - } - return preverified; -} - -template -void TlsEnabled::loadCertificateAuthorities(const WebsocketppContextPtr& ctx) const -{ - if (CAFileNames_.empty()) - { - LOGINFO("No CA file paths defined, trying to use default system path."); - try { - ctx->set_default_verify_paths(); - } catch (const std::exception& e) { - LOGERR("Error while setting default CA paths: %s", e.what()); - } - return; - } - for (const auto& certificateAuthority : CAFileNames_) - { - LOGINFO("Loading Certificate Authority from: %s", certificateAuthority.c_str()); - if (!boost::filesystem::exists(certificateAuthority)) - { - LOGWARN("Certificate: %s doesn't exist.\n", certificateAuthority.c_str()); - continue; - } - try { - ctx->load_verify_file(certificateAuthority); - } catch (const std::exception& e) { - LOGERR("Error while loading certificate: %s, message: %s", certificateAuthority.c_str(), e.what()); - } - } -} - -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Notification.cpp b/helpers/WebSockets/JsonRpc/Notification.cpp deleted file mode 100644 index ad37a3f..0000000 --- a/helpers/WebSockets/JsonRpc/Notification.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Notification.h" - -#include "UtilsLogging.h" - -namespace WebSockets { -namespace JsonRpc { - -Notification::Notification() : WPEFramework::Core::JSONRPC::Message() -{ -} - -bool Notification::isValid() const -{ - if (!JSONRPC.IsSet() || JSONRPC.Value().compare(WPEFramework::Core::JSONRPC::Message::DefaultVersion)) - { - LOGERR("Failed JSONRPC2 version check"); - return false; - } - - if (Method().empty()) - { - LOGERR("Method shouldn't be empty"); - return false; - } - - if (Id.IsSet()) - { - LOGERR("Notification shouln't have jsonrpc id"); - return false; - } - - return true; -} - -std::string Notification::toString() const -{ - std::string request; - ToString(request); - return request; -} - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Notification.h b/helpers/WebSockets/JsonRpc/Notification.h deleted file mode 100644 index afd6a86..0000000 --- a/helpers/WebSockets/JsonRpc/Notification.h +++ /dev/null @@ -1,41 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" - -namespace WebSockets { -namespace JsonRpc { - -class Notification : public WPEFramework::Core::JSONRPC::Message -{ -public: - Notification(); - virtual ~Notification() = default; - - std::string toString() const; - bool isValid() const; -private: - Notification(const Notification&) = delete; - Notification& operator=(const Notification&) = delete; -}; - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Request.cpp b/helpers/WebSockets/JsonRpc/Request.cpp deleted file mode 100644 index 4242647..0000000 --- a/helpers/WebSockets/JsonRpc/Request.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Request.h" - -#include "UtilsLogging.h" - -namespace WebSockets { -namespace JsonRpc { - -std::atomic Request::idSequence(0); - -Request::Request() : WPEFramework::Core::JSONRPC::Message() -{ -} - -uint32_t Request::getId() const -{ - return Id.Value(); -} - -uint32_t Request::generateId() -{ - return (++idSequence); -} - -bool Request::create(std::string method, const JsonObject ¶meters) -{ - if (!JSONRPC.IsSet() || JSONRPC.Value().compare(WPEFramework::Core::JSONRPC::Message::DefaultVersion)) - { - LOGERR("Failed JSONRPC2 version check"); - return false; - } - - if (method.empty()) - { - LOGERR("Provided method is empty"); - return false; - } - Designator = method; - - std::string paramsString; - parameters.ToString(paramsString); - if (!paramsString.empty()) { - Parameters = paramsString; - } - - Id = generateId(); - return true; -} - -std::string Request::toString() const -{ - std::string request; - ToString(request); - return request; -} - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Request.h b/helpers/WebSockets/JsonRpc/Request.h deleted file mode 100644 index 472b98a..0000000 --- a/helpers/WebSockets/JsonRpc/Request.h +++ /dev/null @@ -1,47 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include "Module.h" - -namespace WebSockets { -namespace JsonRpc { - -class Request : public WPEFramework::Core::JSONRPC::Message -{ -public: - Request(); - virtual ~Request() = default; - - bool create(std::string method, const JsonObject ¶meters); - uint32_t getId() const; - std::string toString() const; - -private: - Request(const Request&) = delete; - Request& operator=(const Request&) = delete; - uint32_t generateId(); - - static std::atomic idSequence; -}; - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Response.cpp b/helpers/WebSockets/JsonRpc/Response.cpp deleted file mode 100644 index 0573d3a..0000000 --- a/helpers/WebSockets/JsonRpc/Response.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "Response.h" - -#include "UtilsLogging.h" - -namespace WebSockets { -namespace JsonRpc { - -Response::Response() : WPEFramework::Core::JSONRPC::Message() -{ -} - -uint32_t Response::getId() const -{ - return Id.Value(); -} - -bool Response::isResult() const -{ - return Result.IsSet(); -} - -bool Response::getResult(JsonObject& jsonObject) const -{ - bool result = false; - - if (isResult()) - { - jsonObject.FromString(Result.Value()); - result = true; - } - - return result; -} - -bool Response::isError() const -{ - return Error.IsSet(); -} - -bool Response::getError(JsonObject& jsonObject) const -{ - bool result = false; - - if (isError()) - { - std::string errorString; - Error.ToString(errorString); - jsonObject.FromString(errorString); - result = true; - } - - return result; -} - -bool Response::isValid() const -{ - if (!JSONRPC.IsSet() || JSONRPC.Value().compare(WPEFramework::Core::JSONRPC::Message::DefaultVersion)) - { - LOGERR("Failed jsonrpc version check"); - return false; - } - - if (!Id.IsSet()) - { - LOGERR("Failed jsonrpc id check"); - return false; - } - - if (!Result.IsSet() && !Error.IsSet()) - { - LOGERR("Failed jsonrpc result/error check - both missing"); - return false; - } - - if (Result.IsSet() && Error.IsSet()) - { - LOGERR("Failed jsonrpc result/error check - both set"); - return false; - } - - if (Error.IsSet()) - { - if (!Error.Code.IsSet() || !Error.Text.IsSet()) - { - LOGERR("Failed jsonrpc error code/message check"); - return false; - } - } - - return true; -} - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/JsonRpc/Response.h b/helpers/WebSockets/JsonRpc/Response.h deleted file mode 100644 index 521c0cf..0000000 --- a/helpers/WebSockets/JsonRpc/Response.h +++ /dev/null @@ -1,46 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include "Module.h" - -namespace WebSockets { -namespace JsonRpc { - -class Response : public WPEFramework::Core::JSONRPC::Message -{ -public: - Response(); - virtual ~Response() = default; - - uint32_t getId() const; - bool isResult() const; - bool getResult(JsonObject& jsonObject) const; - bool isError() const; - bool getError(JsonObject& jsonObject) const; - bool isValid() const; - -private: - Response(const Response&) = delete; - Response& operator=(const Response&) = delete; -}; - -} // namespace JsonRpc -} // namespace WebSockets diff --git a/helpers/WebSockets/PingPong/PingPongDisabled.h b/helpers/WebSockets/PingPong/PingPongDisabled.h deleted file mode 100644 index 0aa8c1c..0000000 --- a/helpers/WebSockets/PingPong/PingPongDisabled.h +++ /dev/null @@ -1,47 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include "websocketpp/common/connection_hdl.hpp" - -namespace WebSockets { - -template -class PingPongDisabled -{ -public: - PingPongDisabled() = default; - -protected: - ~PingPongDisabled() = default; - - typedef typename websocketpp::connection_hdl ConnectionHandler; - - void startPing(ConnectionHandler handler) - { - } - -private: - PingPongDisabled(const PingPongDisabled&) = delete; - PingPongDisabled& operator=(const PingPongDisabled&) = delete; - - -}; - -} // namespace WebSockets diff --git a/helpers/WebSockets/PingPong/PingPongEnabled.h b/helpers/WebSockets/PingPong/PingPongEnabled.h deleted file mode 100644 index 741f402..0000000 --- a/helpers/WebSockets/PingPong/PingPongEnabled.h +++ /dev/null @@ -1,143 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include - -#include "websocketpp/common/connection_hdl.hpp" -#include "websocketpp/common/functional.hpp" -#include "websocketpp/error.hpp" - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class PingPongEnabled -{ -public: - typedef typename websocketpp::connection_hdl ConnectionHandler; - PingPongEnabled() = default; - -protected: - ~PingPongEnabled() = default; - void startPing(ConnectionHandler handler); - -private: - void schedule(uint interval, const std::function& cb); - void ping(websocketpp::lib::error_code ecc); - void onPong(ConnectionHandler hdl, std::string); - void onPongTimeout(ConnectionHandler hdl, std::string); - void printConnectionState(const websocketpp::session::state::value& state) const; - - const uint pingInterval_{5000}; - PingPongEnabled(const PingPongEnabled&) = delete; - PingPongEnabled& operator=(const PingPongEnabled&) = delete; -}; - -template -void PingPongEnabled::startPing(ConnectionHandler handler) -{ - LOGINFO(); - Derived& derived = static_cast(*this); - auto connection = derived.getConnection(handler); - if (!connection) - { - LOGERR("Cant get connection."); - return; - } - printConnectionState(connection->get_state()); - connection->set_pong_handler(std::bind(&PingPongEnabled::onPong, this, - websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2)); - connection->set_pong_timeout_handler(std::bind(&PingPongEnabled::onPongTimeout, this, - websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2)); - - schedule(pingInterval_, std::bind(&PingPongEnabled::ping, this, websocketpp::lib::placeholders::_1)); -} - -template -void PingPongEnabled::schedule(uint interval, const std::function& cb) -{ - Derived& derived = static_cast(*this); - derived.endpointImpl_.set_timer( - interval, - websocketpp::lib::bind( - cb, - websocketpp::lib::placeholders::_1 - ) - ); -} - -template -void PingPongEnabled::ping(websocketpp::lib::error_code ecc) -{ - LOGINFO(); - Derived& derived = static_cast(*this); - auto connection = derived.getConnection(derived.connectionHandler_); - if (!connection) - { - // Probably connection closed and cleaned up. - LOGINFO("Cant get connection. Not sending ping."); - return; - } - if (connection->get_state() != websocketpp::session::state::open) - { - // Connection will be/was closed internaly and onClose will be/has been launched - printConnectionState(connection->get_state()); - LOGINFO("Connection state is not open/working. Not sending ping."); - return; - } - websocketpp::lib::error_code ec; - connection->ping("",ec); - if (ec) - { - LOGERR("Sending ping failed, reason: %s", ec.message().c_str()); - return; - } -} - -template -void PingPongEnabled::onPong(ConnectionHandler hdl, std::string) -{ - LOGINFO("Pong received"); - schedule(pingInterval_, std::bind(&PingPongEnabled::ping, this, websocketpp::lib::placeholders::_1)); -} - -template -void PingPongEnabled::onPongTimeout(ConnectionHandler hdl, std::string) -{ - LOGINFO("Pong timeout. Closing connection."); - Derived& derived = static_cast(*this); - derived.closeConnection(); -} - -template -void PingPongEnabled::printConnectionState(const websocketpp::session::state::value& state) const -{ - static std::map m = { - {websocketpp::session::state::connecting, "connecting"}, - {websocketpp::session::state::open, "open"}, - {websocketpp::session::state::closing, "closing"}, - {websocketpp::session::state::closed, "closed"}}; - LOGINFO("Connection state is: %s", m[state].c_str()); -} - -} // namespace WebSockets diff --git a/helpers/WebSockets/Roles/Client.h b/helpers/WebSockets/Roles/Client.h deleted file mode 100644 index 2a1de09..0000000 --- a/helpers/WebSockets/Roles/Client.h +++ /dev/null @@ -1,88 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include - -#include "websocketpp/config/asio_no_tls_client.hpp" -#include "websocketpp/config/asio_client.hpp" -#include "websocketpp/client.hpp" - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class Client -{ -public: - using NotEncryptedEndpointType = websocketpp::client; - using EncryptedEndpointType = websocketpp::client; - - Client() = default; - - bool connect(std::string address, std::function connectionInitializationCallback, - std::function connectionClosedCallback); - void disconnect(); - -protected: - ~Client() = default; - -private: - Client(const Client&) = delete; - Client& operator=(const Client&) = delete; -}; - -template -bool Client::connect(std::string address, std::function connectionInitializationCallback, - std::function connectionClosedCallback) -{ - Derived& derived = static_cast(*this); - const std::string uri = derived.addProtocolToAddress(address); - - LOGINFO("Connecting, uri: %s", uri.c_str()); - - derived.connectionInitializationCallback_ = connectionInitializationCallback; - derived.connectionClosedCallback_ = connectionClosedCallback; - - websocketpp::lib::error_code ec; - auto connection = derived.endpointImpl_.get_connection(uri, ec); - if (ec) { - LOGERR("Can't prepare connection to connect with: %s, reason: %s", uri.c_str(), ec.message().c_str()); - return false; - } - - derived.startEventLoop(); - LOGINFO("Calling connect on: %s\n", uri.c_str()); - derived.endpointImpl_.connect(connection); - return true; -} - -template -void Client::disconnect() -{ - LOGINFO(); - Derived& derived = static_cast(*this); - derived.closeConnection(); - LOGINFO("Disconnection successfull"); -} - -} // namespace WebSockets diff --git a/helpers/WebSockets/Roles/SingleClientServer.h b/helpers/WebSockets/Roles/SingleClientServer.h deleted file mode 100644 index 991606e..0000000 --- a/helpers/WebSockets/Roles/SingleClientServer.h +++ /dev/null @@ -1,98 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include - -#include "websocketpp/config/asio_no_tls.hpp" -#include "websocketpp/config/asio.hpp" -#include "websocketpp/server.hpp" - -#include "Module.h" -#include "UtilsLogging.h" - -namespace WebSockets { - -template -class SingleClientServer -{ -public: - using NotEncryptedEndpointType = websocketpp::server; - using EncryptedEndpointType = websocketpp::server; - - SingleClientServer() = default; - - bool start(int port, std::function connectionInitializationCallback, - std::function connectionClosedCallback); - void stop(); - -protected: - ~SingleClientServer() = default; - -private: - SingleClientServer(const SingleClientServer&) = delete; - SingleClientServer& operator=(const SingleClientServer&) = delete; -}; - -template -bool SingleClientServer::start(int port, std::function connectionInitializationCallback, - std::function connectionClosedCallback) -{ - LOGINFO("Starting websocket server on port: %d", port); - - Derived& derived = static_cast(*this); - derived.connectionInitializationCallback_ = connectionInitializationCallback; - derived.connectionClosedCallback_ = connectionClosedCallback; - - websocketpp::lib::error_code ec; - derived.endpointImpl_.listen(port, ec); - if (ec) { - LOGERR("Failed to start listening, reason: %s", ec.message().c_str()); - return false; - } - - derived.endpointImpl_.start_accept(ec); - if (ec) { - LOGERR("Failed to start server, reason: %s", ec.message().c_str()); - return false; - } - - derived.startEventLoop(); - return true; -} - -template -void SingleClientServer::stop() -{ - LOGINFO(); - Derived& derived = static_cast(*this); - websocketpp::lib::error_code ec; - derived.endpointImpl_.stop_listening(ec); - if (ec) - { - LOGERR("Ordering server to stop listening failed, reason: %s", ec.message().c_str()); - return; - } - derived.closeConnection(); - LOGINFO("Connection ordered to stop and server ordered to stop listening. Server will fully close when 'run' method ends."); -} - -} // namespace WebSockets diff --git a/helpers/WebSockets/WSEndpoint.cpp b/helpers/WebSockets/WSEndpoint.cpp deleted file mode 100644 index 895c1d7..0000000 --- a/helpers/WebSockets/WSEndpoint.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#include "WSEndpoint.h" -#include "CommunicationInterface/BinaryInterface.h" -#include "CommunicationInterface/CommandInterface.h" -#include "CommunicationInterface/JsonRpcInterface.h" - -#include "Roles/SingleClientServer.h" -#include "Roles/Client.h" -#include "PingPong/PingPongEnabled.h" -#include "PingPong/PingPongDisabled.h" -#include "Encryption/TlsEnabled.h" -#include "Encryption/NoEncryption.h" - -#include "UtilsLogging.h" - -namespace WebSockets { - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -WSEndpoint::WSEndpoint() -{ - LOGINFO(); - // Uncomment for connection details - // endpointImpl_.set_access_channels(websocketpp::log::alevel::all); - // endpointImpl_.set_error_channels(websocketpp::log::elevel::all); - endpointImpl_.clear_access_channels(websocketpp::log::alevel::all); - endpointImpl_.clear_error_channels(websocketpp::log::elevel::all); - - registerHandlers(); - - endpointImpl_.init_asio(); - Encryption >::setup(); - endpointImpl_.start_perpetual(); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -WSEndpoint::~WSEndpoint() -{ - LOGINFO(); - endpointImpl_.stop_perpetual(); - closeConnection(); - stopEventLoop(); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::closeConnection() -{ - LOGINFO(); - auto conn = getConnection(connectionHandler_); - if (!conn) - { - LOGINFO("Cant get connection (Probably connection already closed)."); - return; - } - if (conn->get_state() != websocketpp::session::state::open) - { - LOGINFO("Can't close connection which is not open."); - return; - } - - websocketpp::lib::error_code ec; - endpointImpl_.close(connectionHandler_, websocketpp::close::status::going_away, "", ec); - if (ec) { - LOGERR("Closing connection failed, reason: %s", ec.message().c_str()); - } -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::startEventLoop() -{ - LOGINFO(); - if (!eventLoopThread_) - { - LOGINFO("Starting new event loop thread"); - eventLoopThread_ = std::thread([this]() { - LOGINFO("Starting websocket communication on new thread"); - endpointImpl_.run(); - LOGINFO("Event loop thread finished"); - }); - } -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::stopEventLoop() -{ - LOGINFO(); - if (eventLoopThread_ && eventLoopThread_->joinable()) - { - LOGINFO("Event loop thread is joinable. Waiting for join."); - eventLoopThread_->join(); - eventLoopThread_ = boost::none; - } -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::registerHandlers() -{ - LOGINFO(); - endpointImpl_.set_message_handler(std::bind(&WSEndpoint::onMessage, this, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2)); - endpointImpl_.set_open_handler(std::bind(&WSEndpoint::onOpen, this, websocketpp::lib::placeholders::_1)); - endpointImpl_.set_close_handler(std::bind(&WSEndpoint::onClose, this, websocketpp::lib::placeholders::_1)); - endpointImpl_.set_fail_handler(std::bind(&WSEndpoint::onFail, this, websocketpp::lib::placeholders::_1)); - endpointImpl_.set_open_handshake_timeout(5000); - endpointImpl_.set_close_handshake_timeout(5000); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -bool WSEndpoint::send(const std::string& message) -{ - if (message.empty()) - { - LOGERR("Can't send empty message"); - return false; - } - - websocketpp::lib::error_code ec; - endpointImpl_.send(connectionHandler_, message, MessagingInterface::opcode_, ec); - if (ec) - { - LOGERR("Sending failed, reason: %s", ec.message().c_str()); - return false; - } - - return true; -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::onMessage(ConnectionHandler, typename WebsocketppEndpoint::message_ptr msg) -{ - if (msg->get_opcode() != MessagingInterface::opcode_) - { - LOGERR("Received message is not tagged with text opcode, droping."); - return; - } - MessagingInterface::onMessage(msg->get_payload()); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::onOpen(ConnectionHandler handler) -{ - LOGINFO("New connection opened."); - connectionHandler_ = handler; - connectionInitializationCallback_(ConnectionInitializationResult(true)); - PingPong::startPing(handler); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::onFail(ConnectionHandler handler) -{ - LOGINFO("Connection attempt failure."); - - const auto& connection = getConnection(handler); - const auto& connectionEc = connection->get_ec(); - if (connectionEc) - { - LOGINFO("Connection error: %s. Category: %s. Value: %d", connectionEc.message().c_str(), - connectionEc.category().name(), connectionEc.value()); - } - - ConnectionInitializationResult result(false); - Encryption >::setAuthenticationState(result, handler); - - connectionInitializationCallback_(result); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -void WSEndpoint::onClose(ConnectionHandler) -{ - LOGINFO("Connection closed."); - connectionClosedCallback_(); -} - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -typename WSEndpoint::ConnectionPtr -WSEndpoint::getConnection(ConnectionHandler handler) -{ - websocketpp::lib::error_code handlerToConnectionEc; - auto connection = endpointImpl_.get_con_from_hdl(handler, handlerToConnectionEc); - if (handlerToConnectionEc) - { - LOGERR("Can't get connection from handler, reason: %s", handlerToConnectionEc.message().c_str()); - return {}; - } - return connection; -} - -// All used configurations need to be listed here to generate needed symbols. -// Without those symbols there is a runtime crash. - -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; -template class WSEndpoint; - -} // namespace WebSockets diff --git a/helpers/WebSockets/WSEndpoint.h b/helpers/WebSockets/WSEndpoint.h deleted file mode 100644 index af1140c..0000000 --- a/helpers/WebSockets/WSEndpoint.h +++ /dev/null @@ -1,79 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2022 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once -#include -#include -#include -#include -#include - -#include "ConnectionInitializationResult.h" -#include "websocketpp/server.hpp" - -namespace WebSockets { - -template< - template typename Role, - template typename MessagingInterface, - template typename PingPong, - template typename Encryption -> -class WSEndpoint : public Role >, - public MessagingInterface >, - private PingPong >, - public Encryption, Role > > -{ -public: - WSEndpoint(); - ~WSEndpoint(); - -private: - WSEndpoint(const WSEndpoint&) = delete; - WSEndpoint& operator=(const WSEndpoint&) = delete; - - friend Role; - friend MessagingInterface; - friend PingPong; - friend Encryption >; - - using WebsocketppEndpoint = typename Encryption >::EndpointType; - using ConnectionPtr = typename WebsocketppEndpoint::connection_ptr; - using ConnectionHandler = websocketpp::connection_hdl; - - bool send(const std::string& message); - void closeConnection(); - void startEventLoop(); - void stopEventLoop(); - WSEndpoint::ConnectionPtr getConnection(ConnectionHandler handler); - - void registerHandlers(); - void onMessage(ConnectionHandler, typename WebsocketppEndpoint::message_ptr msg); - void onOpen(ConnectionHandler); - void onFail(ConnectionHandler); - void onClose(ConnectionHandler); - - WebsocketppEndpoint endpointImpl_; - ConnectionHandler connectionHandler_; - boost::optional eventLoopThread_; - std::function connectionInitializationCallback_; - std::function connectionClosedCallback_; -}; - -} // namespace WebSockets diff --git a/helpers/WsManager.h b/helpers/WsManager.h deleted file mode 100644 index af24d86..0000000 --- a/helpers/WsManager.h +++ /dev/null @@ -1,586 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include "UtilsLogging.h" -#include "WebSocketLink.h" - - -// TODO: Remove once IsNullValue() in core/JSON.h is fixed -// and replace StreamJSONOneShotType with StreamJSONType -#include "StreamJSONOneShot.h" - -#define DEFAULT_SOCKET_ADDRESS "127.0.0.1" -using namespace WPEFramework; - -class WebSocketConnectionManager -{ -public: - ~WebSocketConnectionManager() { - if (mChannel) { - delete mChannel; - mChannel = nullptr; - } - } - class Config : public Core::JSON::Container - { - public: - Config(const Config &) = delete; - Config &operator=(const Config &) = delete; - Config(Config &&) = delete; - Config &operator=(Config &&) = delete; - - Config(const std::string socketAddress = DEFAULT_SOCKET_ADDRESS) - : Core::JSON::Container(), Connector(socketAddress) - { - Add(_T("connector"), &Connector); - } - ~Config() override = default; - - public: - Core::JSON::String Connector; - }; - - // Forward declarations - public: - class WebSocketChannel; - - // WebSocket JSON Object Factory - class JSONObjectFactory : public Core::FactoryType - { - public: - JSONObjectFactory():Core::FactoryType(), _jsonRPCFactory(5) {} - JSONObjectFactory(const JSONObjectFactory &) = delete; - JSONObjectFactory &operator=(const JSONObjectFactory &) = delete; - ~JSONObjectFactory() = default; - - public: - static JSONObjectFactory &Instance(){ - static JSONObjectFactory _singleton; - return (_singleton); - } - Core::ProxyType Element(const string &identifier VARIABLE_IS_NOT_USED) { - Core::ProxyType> message = _jsonRPCFactory.Element(); - return Core::ProxyType(message); - } - - private: - Core::ProxyPoolType> _jsonRPCFactory; - }; - - // WebSocket Server implementation - public: - class WebSocketServer - : public Core::StreamJSONOneShotType, JSONObjectFactory &, Core::JSON::IElement> - { - public: - WebSocketServer() = delete; - WebSocketServer &operator=(const WebSocketServer &) = delete; - typedef Core::StreamJSONOneShotType, JSONObjectFactory &, Core::JSON::IElement> BaseClass; - - public: - WebSocketServer(const SOCKET &connector, const Core::NodeId &remoteNode, Core::SocketServerType *parent) : - WebSocketServer::BaseClass( - 5, - WebSocketConnectionManager::JSONObjectFactory::Instance(), - false, false, false, - connector, - remoteNode.AnyInterface(), - 8096, 8096), - _id(0), - _parent(static_cast(*parent)), - _queue(10){ - LOGTRACE("Connector value: %d", static_cast(connector)); - LOGTRACE("Remote host: %s", remoteNode.HostAddress().c_str()); - } - ~WebSocketServer() { - _qLock.Lock(); - _queue.Clear(); - _qLock.Unlock(); - LOGTRACE("WebSocketServer destructed for connectionId: %d", _id); - - } - - public: - void Received(Core::ProxyType &jsonObject){ - - uint32_t connectionId = _id; - - if (jsonObject.IsValid() == false) - { - LOGERR("WebSocketServer: Invalid JSON object received"); - } - else - { - Core::ProxyType message = Core::ProxyType(jsonObject); - // Call internal ProcessMessage - WebSocketConnectionManager::WebSocketServer::ProcessMessage(message, connectionId); - } - } - void Send(Core::ProxyType &jsonObject) { - if (jsonObject.IsValid() == false) - { - LOGERR("WebSocketServer: Invalid JSON object to send"); - } - else - { - WebSocketConnectionManager::WebSocketServer::ToMessage(jsonObject); - } - }; - void StateChange(){ - if (this->IsOpen()) - { - LOGTRACE("Open - OK"); - const std::string &query = Link().Query(); - if (_parent.Interface()._authHandler != nullptr) { - bool authResult = _parent.Interface()._authHandler(_id, query); - if (!authResult) { - LOGERR("Authentication failed for query: %s", query.c_str()); - this->Close(0); - return; - } - LOGTRACE("Authentication succeeded"); - } else { - LOGWARN("No authentication handler set, proceeding without authentication"); - } - } - else if(this->IsSuspended()) - { - LOGTRACE("Closed - %s", this->IsSuspended() ? _T("SUSPENDED") : _T("OK")); - if (_parent.Interface()._disconnectHandler != nullptr) { - _parent.Interface()._disconnectHandler(Id()); - } - } - } - - bool IsIdle() const { - return (true); - } - - void SendJSONRPCResponse(const std::string &result, int requestId, uint32_t connectionId) { - Core::ProxyType response = Core::ProxyType::Create(); - response->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - response->Id = requestId; - response->Result = result; - - LOGDBG("[SendJSONRPCResponse] Sending response for requestId=%d, connectionId=%d", requestId, connectionId); - LOGDBG("[SendJSONRPCResponse] Response: %s", result.c_str()); - - // Send the response back to the WebSocket client - this->Submit(Core::ProxyType(response)); - } - - private: - friend class Core::SocketServerType; - - uint32_t Id() { - return (_id); - } - - void Id(const uint32_t id){ - LOGTRACE("Assigning connectionId: %d", id); - _id = id; - - // Process any pending messages for this connection - _qLock.Lock(); - while (_queue.Count() > 0) { - auto message = _queue[0]; - if (message.IsValid()) { - LOGDBG("Processing pending message for connectionId: %d", _id); - WebSocketConnectionManager::WebSocketServer::ProcessMessage(message, _id); - } - _queue.Remove(0, message); - } - _qLock.Unlock(); - } - - void ToMessage(const Core::ProxyType &jsonObject) { - string jsonMessage; - jsonObject->ToString(jsonMessage); - LOGTRACE("WebSocket Sent: %s", jsonMessage.c_str()); - } - void ProcessMessage(Core::ProxyType &message, uint32_t connectionId) { - // Check for message->Id.IsSet() - if(!message->Id.IsSet()) { - string jsonMessage; - message->ToString(jsonMessage); - // Log an Error for this usecase - LOGERR("Message MUST contain an id field %s", jsonMessage.c_str()); - return; - } - - int requestId = message->Id.Value(); - - if (_id == 0) { - string jsonMessage; - message->ToString(jsonMessage); - LOGERR("Connection ID Not set adding request to Pending queue %s", jsonMessage.c_str()); - AddToPending(message); - return; - } - - // Extract method name from designator - if(!message->Designator.IsSet()) { - SendJSONRPCResponse(R"({"error": "Message MUST contain a method field"})", requestId, connectionId); - return; - } - - std::string methodName = message->Designator.Value(); - - LOGTRACE("[ProcessMessage] Method: %s, RequestId: %d, ConnectionId: %d", - methodName.c_str(), requestId, connectionId); - - // Extract params once for reuse - std::string params = "{}"; // Default empty params - if (message->Parameters.IsSet() && !message->Parameters.Value().empty()) - { - params = message->Parameters.Value(); - } - - // SYNCHRONOUS PROCESSING - try - { - auto& manager = _parent.Interface(); - if (manager._messageHandler) { - manager._messageHandler(methodName, params, requestId, _id); - } else { - SendJSONRPCResponse(R"({"error": "Message handler not set"})", requestId, connectionId); - } - } - catch (const std::exception &e) - { - LOGERR("[ProcessMessage] Exception during synchronous processing: %s", e.what()); - std::string errorResponse = R"({"error": "Processing exception", "details": ")" + std::string(e.what()) + R"("})"; - WebSocketConnectionManager::WebSocketServer::SendJSONRPCResponse(errorResponse, requestId, connectionId); - } - catch (...) - { - LOGERR("[ProcessMessage] Unknown exception during synchronous processing"); - WebSocketConnectionManager::WebSocketServer::SendJSONRPCResponse(R"({"error": "Unknown processing exception"})", requestId, connectionId); - } - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Forward to automation server after processing the request - if (_parent.Interface()._automationId > 0) { - AutomationMessage automationMsg; - - automationMsg.ConnectionId = connectionId; - automationMsg.Type = "request"; - automationMsg.Id = requestId; - automationMsg.Method = methodName; - automationMsg.Params = params; // Reuse the params variable extracted above - - string jsonMsg; - automationMsg.ToString(jsonMsg); - - LOGINFO("[Automation] Forwarding request: %s", jsonMsg.c_str()); - Core::ProxyType automationNotif = Core::ProxyType::Create(); - automationNotif->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - automationNotif->Designator = "automationUpdate"; - automationNotif->Parameters = jsonMsg; - _parent.Interface().mChannel->Submit(_parent.Interface()._automationId, Core::ProxyType(automationNotif)); - } - #endif - } - - void FromMessage(Core::JSON::IElement *jsonObject, const Core::ProxyType &message){ - jsonObject->FromString(message->Parameters.Value()); - } - - // New Method add message to the _queue - void AddToPending(Core::ProxyType& element) - { - _qLock.Lock(); - if (_queue.Count() == 10 ) { - LOGERR("Queue full for %d processing error for first entry", _id); - // Remove the first entry - auto firstElement = _queue[0]; - _queue.Remove(0, firstElement); - std::string errorResponse = R"({"error": "Message MUST contain a method field"})"; - WebSocketConnectionManager::WebSocketServer::SendJSONRPCResponse(errorResponse, firstElement->Id.Value(), _id); - } - // - _queue.Add(element); - LOGTRACE("Message queued for connectionId: %d, queue size: %d", _id, static_cast(_queue.Count())); - - _qLock.Unlock(); - } - - private: - uint32_t _id; - WebSocketChannel &_parent; - Core::CriticalSection _qLock; - Core::ProxyList _queue; - }; - - // WebSocket Channel management - class WebSocketChannel : public Core::SocketServerType - { - public: - WebSocketChannel() = delete; - WebSocketChannel(const WebSocketChannel ©) = delete; - WebSocketChannel &operator=(const WebSocketChannel &) = delete; - - public: - WebSocketChannel(const WPEFramework::Core::NodeId &remoteNode, WebSocketConnectionManager &parent): - Core::SocketServerType(remoteNode), - _parent(parent) { - Core::SocketServerType::Open(Core::infinite); - } - ~WebSocketChannel() { - Core::SocketServerType::Close(1000); - } - WebSocketConnectionManager &Interface() { - return _parent; - } - - private: - WebSocketConnectionManager &_parent; - }; - -public: - // Message handler callback type - using MessageHandler = std::function; - using AuthHandler = std::function; - using DisconnectHandler = std::function; - -#ifdef ENABLE_APP_GATEWAY_AUTOMATION - // JSON container classes for automation messages - class AutomationMessage : public Core::JSON::Container { - public: - AutomationMessage() : Core::JSON::Container() { - Add(_T("connectionId"), &ConnectionId); - Add(_T("type"), &Type); - Add(_T("id"), &Id); - Add(_T("method"), &Method); - Add(_T("params"), &Params); - Add(_T("payload"), &Payload); - } - Core::JSON::DecUInt32 ConnectionId; - Core::JSON::String Type; - Core::JSON::DecUInt32 Id; - Core::JSON::String Method; - Core::JSON::String Params; - Core::JSON::String Payload; - }; - - class ConnectionUpdate : public Core::JSON::Container { - public: - ConnectionUpdate() : Core::JSON::Container() { - Add(_T("connectionId"), &ConnectionId); - Add(_T("appId"), &AppId); - Add(_T("connected"), &Connected); - } - Core::JSON::DecUInt32 ConnectionId; - Core::JSON::String AppId; - Core::JSON::Boolean Connected; - }; -#endif - - // New method to add a message Handler into ProcessMessage method - void SetMessageHandler(const MessageHandler& handler) { _messageHandler = handler; } - - void SetAuthHandler(const AuthHandler& handler) { _authHandler = handler; } - - void SetDisconnectHandler(DisconnectHandler handler) { _disconnectHandler = handler; } - - // NEW: Setter for automation ID - void SetAutomationId(uint32_t automationId) { - _automationId = automationId; - LOGINFO("Automation ID set to: %d", _automationId); - } - -private: - // Helper method to forward messages to automation server - void ForwardToAutomation(const std::string& designator, const std::string& payload) { - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - if (_automationId > 0) { - Core::ProxyType automationNotif = Core::ProxyType::Create(); - automationNotif->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - automationNotif->Designator = designator; - automationNotif->Parameters = payload; - mChannel->Submit(_automationId, Core::ProxyType(automationNotif)); - LOGINFO("[Automation] Forwarded to automation server: %s", payload.c_str()); - } - #endif - } - -public: - // Create a new method which can send message to a given connection id using the connection registry - // Use the SendJSONRPCResponse in Websocket Server to send the message - bool SendMessageToConnection(const uint32_t connectionId, const std::string &result, const int requestId) - { - Core::ProxyType response = Core::ProxyType::Create(); - response->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - response->Id = requestId; - - Core::JSONRPC::Message::Info info; - if (info.FromString(result) && info.Code.IsSet() && info.Text.IsSet()) { - response->Error = info; - } else { - response->Result = result; - } - - - - LOGTRACE("[SendJSONRPCResponse] Sending response for requestId=%d, connectionId=%d response=%s", requestId, connectionId, result.c_str()); - - // Send the response back to the WebSocket client - mChannel->Submit(connectionId, Core::ProxyType(response)); - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Forward to automation server after sending response - if (_automationId > 0 && connectionId != _automationId) { - AutomationMessage automationMsg; - - automationMsg.ConnectionId = connectionId; - automationMsg.Type = "response"; - automationMsg.Id = requestId; - automationMsg.Payload = result; - - string jsonMsg; - automationMsg.ToString(jsonMsg); - ForwardToAutomation("automationUpdate", jsonMsg); - } - #endif - - return true; - } - - bool DispatchNotificationToConnection(const uint32_t connectionId, const std::string &designator, const std::string &payload) - { - Core::ProxyType event = Core::ProxyType::Create(); - event->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - event->Designator = designator; - event->Parameters = payload; - LOGTRACE("Emit Event for method=%s, connectionId=%d params=%s", designator.c_str(), connectionId, payload.c_str()); - mChannel->Submit(connectionId, Core::ProxyType(event)); - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Forward to automation server after sending notification - if (_automationId > 0 && connectionId != _automationId) { - AutomationMessage automationMsg; - - automationMsg.ConnectionId = connectionId; - automationMsg.Type = "notification"; - automationMsg.Method = designator; - automationMsg.Params = payload; - - string jsonMsg; - automationMsg.ToString(jsonMsg); - ForwardToAutomation("automationUpdate", jsonMsg); - } - #endif - - return true; - } - - bool SendRequestToConnection(const uint32_t connectionId, const std::string &designator, const uint32_t requestId, const std::string ¶ms) - { - Core::ProxyType request = Core::ProxyType::Create(); - request->JSONRPC = Core::JSONRPC::Message::DefaultVersion; - request->Id = requestId; - request->Designator = designator; - request->Parameters = params; - - LOGTRACE("Send Request for method=%s, connectionId=%d params=%s", designator.c_str(), connectionId, params.c_str()); - mChannel->Submit(connectionId, Core::ProxyType(request)); - - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - // Forward to automation server after sending request - if (_automationId > 0 && connectionId != _automationId) { - AutomationMessage automationMsg; - - automationMsg.ConnectionId = connectionId; - automationMsg.Type = "request"; - automationMsg.Id = requestId; - automationMsg.Method = designator; - automationMsg.Params = params; - - string jsonMsg; - automationMsg.ToString(jsonMsg); - ForwardToAutomation("automationUpdate", jsonMsg); - } - #endif - - return true; - } - - // Method to update connection status to automation server - void UpdateConnection(uint32_t connectionId, const std::string& appId, bool connected) { - #ifdef ENABLE_APP_GATEWAY_AUTOMATION - if (_automationId > 0) { - ConnectionUpdate updateMsg; - - updateMsg.ConnectionId = connectionId; - updateMsg.AppId = appId; - updateMsg.Connected = connected; - - string jsonMsg; - updateMsg.ToString(jsonMsg); - ForwardToAutomation("connectionUpdate", jsonMsg); - } - #endif - } - - // New Method to start websocket channel using NodeId - bool Start(const Core::NodeId &remoteNode) - { - try - { - mChannel = new WebSocketChannel(remoteNode, *this); - if (mChannel == nullptr) - { - LOGERR("Failed to create WebSocket channel"); - return false; - } - - LOGINFO("WebSocket channel started successfully on %s %d", remoteNode.HostAddress().c_str(), remoteNode.PortNumber()); - return true; - } - catch (const std::exception &e) - { - LOGERR("Exception while starting WebSocket channel: %s", e.what()); - return false; - } - catch (...) - { - LOGERR("Unknown exception while starting WebSocket channel"); - return false; - } - } - - // Close connection for a given connection id - void Close(const uint32_t connectionId) { - const auto& client = mChannel->Client(connectionId); - client->Close(0); - } - -private: - - MessageHandler _messageHandler; - AuthHandler _authHandler; - DisconnectHandler _disconnectHandler; - WebSocketChannel *mChannel = nullptr; - uint32_t _automationId = 0; -}; diff --git a/helpers/cSettings.h b/helpers/cSettings.h deleted file mode 100644 index d6590e1..0000000 --- a/helpers/cSettings.h +++ /dev/null @@ -1,211 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#pragma once - -#include -#include -#include -#include -#include - -#include "UtilsfileExists.h" - -using namespace std; - -class cSettings { - std::string filename; - JsonObject data; - -public: - /*** - * @brief : Constructor. - * @return : nil. - */ - cSettings(std::string file) - { - filename = file; - if (!readFromFile()) { - /* File not present; create a new one assuming a fresh partition. */ - std::fstream fs; - fs.open(filename.c_str(), std::fstream::in | std::fstream::out | std::fstream::app); - if (!fs.is_open()) { - std::cout << "Error:[ctor cSettings] unable to open configuration file." << std::endl; - } else { - fs << flush; - fs.close(); - } - } - } - - /*** - * @brief : Destructor. - * @return : nil. - */ - ~cSettings() = default; - - /*** - * @brief : Get value of given key. - * @param1[in] : key - * @return : the value to the corresponding key - */ - JsonValue getValue(std::string key) - { - return data.Get(key.c_str()); - } - - /*** - * @brief : Set value of given key. - * @param1[in] : key - * @param2[in] : value - * @return : True if setvalue successfull, else False - */ - bool setValue(std::string key, std::string value) - { - data[key.c_str()] = value; - return writeToFile(); - } - - /*** - * @brief : Set value of given key. - * @param1[in] : key - * @param2[in] : value - * @return : True if setvalue successfull, else False - */ - bool setValue(std::string key, int value) - { - data[key.c_str()] = value; - return writeToFile(); - } - - /*** - * @brief : Set value of given key. - * @param1[in] : key - * @param2[in] : value - * @return : True if setvalue successfull, else False - */ - bool setValue(std::string key, bool value) - { - data[key.c_str()] = value; - return writeToFile(); - } - - /*** - * @brief : Check if a particular key is set. - * @param1[in] : key - * @return : True if key is already set, else False - */ - bool contains(std::string key) - { - bool resp = false; - if (data.HasLabel(key.c_str())) { - if (data[key.c_str()].String().empty()) { - resp = false; - } else { - resp = true; - } - } else { - resp = false; - } - return resp; - } - - /*** - * @brief : Remove a particular key-value pair. - * @param1[in] : key - * @return : True if key is key-value pair removed, else False - */ - bool remove(std::string key) - { - bool status = false; - /* - * Noticed that there is an error with the Remove function. - * work around is to assign a null value to the key and handle it - * accordingly. - */ - data[key.c_str()] = ""; - data.Remove(key.c_str()); - if (!contains(key)) { - if (writeToFile()) { - status = true; - } else { - status = false; - } - } else { - status = false; - } - return status; - } - - /*** - * @brief : Update new inserts into the json object onto file. - * @return : False if timer thread couldn't be started. - */ - bool writeToFile() - { - bool status = false; - - if (Utils::fileExists(filename.c_str())) { - ofstream ofile; - ofile.open(filename.c_str(), ios::out); - if (ofile) { - JsonObject::Iterator iterator = data.Variants(); - while (iterator.Next()) { - if (!data[iterator.Label()].String().empty()) { - ofile << iterator.Label() << "=" << data[iterator.Label()].String() << endl; - } else { - continue; - } - } - status = true; - ofile.close(); - } else { - status = false; - } - } - return status; - } - - /*** - * @brief : Initialise the jsonobject from a given conf file. - * @return : False if file couldn't be accessed, else True. - */ - bool readFromFile() - { - bool retStatus = false; - std::string content; - if (!Utils::fileExists(filename.c_str())) { - return retStatus; - } - fstream ifile(filename, ios::in); - if (ifile) { - while (!ifile.eof()) { - std::getline(ifile, content); - size_t pos = content.find_last_of("="); - if (std::string::npos != pos) { - data[(content.substr(0, pos).c_str())] = content.substr(pos + 1, std::string::npos); - } - retStatus = true; - } - } else { - //Do nothing. - } - return retStatus; - } -}; diff --git a/helpers/frontpanel.cpp b/helpers/frontpanel.cpp deleted file mode 100644 index 8e6901b..0000000 --- a/helpers/frontpanel.cpp +++ /dev/null @@ -1,713 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -/** -* @defgroup servicemanager -* @{ -* @defgroup src -* @{ -**/ - -//#define USE_DS //TODO - this was defined in servicemanager.pro for all STB builds. Not sure where to put it except here for now -//#define HAS_API_POWERSTATE - -#include "frontpanel.h" -#ifdef USE_DS - #include "frontPanelConfig.hpp" - #include "frontPanelTextDisplay.hpp" - #include "manager.hpp" -#endif - -#include -#include -#include -#include - -#if defined(HAS_API_POWERSTATE) -#include "libIBus.h" -#include - -using namespace WPEFramework; -using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; -#endif - -#include "UtilsJsonRpc.h" -#include "UtilsLogging.h" -#include "UtilssyncPersistFile.h" -#include "PowerManagerInterface.h" - -#define FP_SETTINGS_FILE_JSON "/opt/fp_service_preferences.json" - -/* -Requirement now - Ability to get/set Led brightness - Ability to power off/on a led - -*/ - -namespace WPEFramework -{ - - namespace Plugin - { - CFrontPanel* CFrontPanel::s_instance = NULL; - static int globalLedBrightness = 100; -#ifdef CLOCK_BRIGHTNESS_ENABLED - static int clockBrightness = 100; -#endif - int CFrontPanel::initDone = 0; - static bool isMessageLedOn = false; - static bool isRecordLedOn = false; -#ifdef CLOCK_BRIGHTNESS_ENABLED - static bool isClockOn; -#endif - static bool powerStatus = false; //Check how this works on xi3 and rng's - static bool started = false; - static int m_numberOfBlinks = 0; - static int m_maxNumberOfBlinkRepeats = 0; - static int m_currentBlinkListIndex = 0; - static std::vector m_lights; - static device::List fpIndicators; - static PowerManagerInterfaceRef _powerManagerPlugin; - - static Core::TimerType blinkTimer(64 * 1024, "BlinkTimer"); - - namespace - { - - struct Mapping - { - const char *IArmBusName; - const char *SvcManagerName; - }; - - static struct Mapping name_mappings[] = { - { "Record" , "record_led"}, - { "Message" , "data_led"}, - { "Power" , "power_led"}, - // TODO: add your mappings here - // { , }, - { 0, 0} - }; - - std::string svc2iarm(const std::string &name) - { - const char *s = name.c_str(); - - int i = 0; - while (name_mappings[i].SvcManagerName) - { - if (strcmp(s, name_mappings[i].SvcManagerName) == 0) - return name_mappings[i].IArmBusName; - i++; - } - return name; - } - } - - CFrontPanel::CFrontPanel() - : m_blinkTimer(this) - , m_isBlinking(false) - { - } - - CFrontPanel* CFrontPanel::instance(PluginHost::IShell *service) - { - if (!initDone) - { - if (nullptr != service) - { - _powerManagerPlugin = PowerManagerInterfaceBuilder(_T("org.rdk.PowerManager")) - .withIShell(service) - .withRetryIntervalMS(200) - .withRetryCount(25) - .createInterface(); - } - if (!s_instance) - s_instance = new CFrontPanel; -#ifdef USE_DS - try - { - LOGINFO("Front panel init"); - fpIndicators = device::FrontPanelConfig::getInstance().getIndicators(); - - for (uint i = 0; i < fpIndicators.size(); i++) - { - std::string IndicatorNameIarm = fpIndicators.at(i).getName(); - - auto it = std::find(m_lights.begin(), m_lights.end(), IndicatorNameIarm); - if (m_lights.end() == it) - { - m_lights.push_back(IndicatorNameIarm); - } - } - -#if defined(HAS_API_POWERSTATE) - { - Core::hresult res = Core::ERROR_GENERAL; - PowerState pwrStateCur = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - PowerState pwrStatePrev = WPEFramework::Exchange::IPowerManager::POWER_STATE_UNKNOWN; - ASSERT (_powerManagerPlugin); - if (_powerManagerPlugin) { - res = _powerManagerPlugin->GetPowerState(pwrStateCur, pwrStatePrev); - if (Core::ERROR_NONE == res) - { - if (pwrStateCur == WPEFramework::Exchange::IPowerManager::POWER_STATE_ON) - powerStatus = true; - } - } - } -#endif -#ifdef CLOCK_BRIGHTNESS_ENABLED - clockBrightness = device::FrontPanelTextDisplay::getInstance("Text").getTextBrightness(); - device::FrontPanelTextDisplay::getInstance("Text").setTextBrightness(clockBrightness); -#endif - globalLedBrightness = device::FrontPanelIndicator::getInstance("Power").getBrightness(); - LOGINFO("Power light brightness, %d, power status %d", globalLedBrightness, powerStatus); - - for (uint i = 0; i < fpIndicators.size(); i++) - { - LOGWARN("Initializing light %s", fpIndicators.at(i).getName().c_str()); - if (powerStatus) - device::FrontPanelIndicator::getInstance(fpIndicators.at(i).getName()).setBrightness(globalLedBrightness); - - device::FrontPanelIndicator::getInstance(fpIndicators.at(i).getName()).setState(false); - } - - if (powerStatus) - device::FrontPanelIndicator::getInstance("Power").setState(true); - - } - catch (...) - { - LOGERR("Exception Caught during [CFrontPanel::instance]\r\n"); - } - initDone=1; -#endif - } - - return s_instance; - } - - bool CFrontPanel::start() - { - LOGWARN("Front panel start"); - try - { - if (powerStatus) - device::FrontPanelIndicator::getInstance("Power").setState(true); - - device::List fpIndicators = device::FrontPanelConfig::getInstance().getIndicators(); - for (uint i = 0; i < fpIndicators.size(); i++) - { - std::string IndicatorNameIarm = fpIndicators.at(i).getName(); - - auto it = std::find(m_lights.begin(), m_lights.end(), IndicatorNameIarm); - if (m_lights.end() == it) - m_lights.push_back(IndicatorNameIarm); - } - } - catch (...) - { - LOGERR("Frontpanel Exception Caught during [%s]\r\n", __func__); - } - if (!started) - { - m_numberOfBlinks = 0; - m_maxNumberOfBlinkRepeats = 0; - m_currentBlinkListIndex = 0; - started = true; - } - return true; - } - - bool CFrontPanel::stop() - { - stopBlinkTimer(); - return true; - } - - void CFrontPanel::setPowerStatus(bool bPowerStatus) - { - powerStatus = bPowerStatus; - } - - std::string CFrontPanel::getLastError() - { - return lastError_; - } - - void CFrontPanel::addEventObserver(FrontPanel* o) - { - - auto it = std::find(observers_.begin(), observers_.end(), o); - - if (observers_.end() == it) - observers_.push_back(o); - } - - void CFrontPanel::removeEventObserver(FrontPanel* o) - { - observers_.remove(o); - } - - bool CFrontPanel::setBrightness(int fp_brightness) - { - stopBlinkTimer(); - globalLedBrightness = fp_brightness; - - try - { - for (uint i = 0; i < fpIndicators.size(); i++) - { - device::FrontPanelIndicator::getInstance(fpIndicators.at(i).getName()).setBrightness(globalLedBrightness); - } - } - catch (...) - { - LOGERR("Frontpanel Exception Caught during [%s]\r\n",__func__); - } - - powerOnLed(FRONT_PANEL_INDICATOR_ALL); - return true; - } - - int CFrontPanel::getBrightness() - { - try - { - globalLedBrightness = device::FrontPanelIndicator::getInstance("Power").getBrightness(); - LOGWARN("Power light brightness, %d\n", globalLedBrightness); - } - catch (...) - { - LOGERR("Frontpanel Exception Caught during [%s]\r\n", __func__); - } - - return globalLedBrightness; - } - -#ifdef CLOCK_BRIGHTNESS_ENABLED - bool CFrontPanel::setClockBrightness(int brightness) - { - clockBrightness = brightness; - powerOnLed(FRONT_PANEL_INDICATOR_CLOCK); - return true; - } - - int CFrontPanel::getClockBrightness() - { - try - { - clockBrightness = device::FrontPanelTextDisplay::getInstance("Text").getTextBrightness(); - } - catch (...) - { - LOGERR("FrontPanel Exception Caught during [%s]\r\n", __func__); - } - - return clockBrightness; - } -#endif - - bool CFrontPanel::powerOnLed(frontPanelIndicator fp_indicator) - { - stopBlinkTimer(); - try - { - if (powerStatus) - { - switch (fp_indicator) - { - case FRONT_PANEL_INDICATOR_CLOCK: -#ifdef CLOCK_BRIGHTNESS_ENABLED - isClockOn = true; - device::FrontPanelTextDisplay::getInstance("Text").setTextBrightness(clockBrightness); -#endif - break; - case FRONT_PANEL_INDICATOR_MESSAGE: - isMessageLedOn = true; - device::FrontPanelIndicator::getInstance("Message").setState(true); - break; - case FRONT_PANEL_INDICATOR_RECORD: - isRecordLedOn = true; - device::FrontPanelIndicator::getInstance("Record").setState(true); - break; - case FRONT_PANEL_INDICATOR_REMOTE: - device::FrontPanelIndicator::getInstance("Remote").setState(true); - break; - case FRONT_PANEL_INDICATOR_RFBYPASS: - device::FrontPanelIndicator::getInstance("RfByPass").setState(true); - break; - case FRONT_PANEL_INDICATOR_ALL: - if (isMessageLedOn) - device::FrontPanelIndicator::getInstance("Message").setState(true); - if (isRecordLedOn) - device::FrontPanelIndicator::getInstance("Record").setState(true); - device::FrontPanelIndicator::getInstance("Power").setState(true); - break; - case FRONT_PANEL_INDICATOR_POWER: - //LOGWARN("CFrontPanel::powerOnLed() - FRONT_PANEL_INDICATOR_POWER not handled"); - device::FrontPanelIndicator::getInstance("Power").setState(true); - break; - } - } - } - catch (...) - { - LOGERR("FrontPanel Exception Caught during [%s]\r\n", __func__); - return false; - } - return true; - } - - bool CFrontPanel::powerOffLed(frontPanelIndicator fp_indicator) - { - stopBlinkTimer(); - try - { - switch (fp_indicator) - { - case FRONT_PANEL_INDICATOR_CLOCK: -#ifdef CLOCK_BRIGHTNESS_ENABLED - isClockOn = false; - device::FrontPanelTextDisplay::getInstance("Text").setTextBrightness(0); -#endif - break; - case FRONT_PANEL_INDICATOR_MESSAGE: - isMessageLedOn = false; - device::FrontPanelIndicator::getInstance("Message").setState(false); - break; - case FRONT_PANEL_INDICATOR_RECORD: - isRecordLedOn = false; - device::FrontPanelIndicator::getInstance("Record").setState(false); - break; - case FRONT_PANEL_INDICATOR_REMOTE: - device::FrontPanelIndicator::getInstance("Remote").setState(false); - break; - case FRONT_PANEL_INDICATOR_RFBYPASS: - device::FrontPanelIndicator::getInstance("RfByPass").setState(false); - break; - case FRONT_PANEL_INDICATOR_ALL: - for (uint i = 0; i < fpIndicators.size(); i++) - { - //LOGWARN("powerOffLed for Indicator %s", QString::fromStdString(fpIndicators.at(i).getName()).toUtf8().constData()); - LOGWARN("powerOffLed for Indicator %s", fpIndicators.at(i).getName().c_str()); - device::FrontPanelIndicator::getInstance(fpIndicators.at(i).getName()).setState(false); - } - break; - case FRONT_PANEL_INDICATOR_POWER: - //LOGWARN("CFrontPanel::powerOffLed() - FRONT_PANEL_INDICATOR_POWER not handled"); - device::FrontPanelIndicator::getInstance("Power").setState(false); - break; - } - } - catch (...) - { - LOGERR("FrontPanel Exception Caught during [%s]\r\n", __func__); - return false; - } - return true; - } - - - bool CFrontPanel::powerOffAllLed() - { - powerOffLed(FRONT_PANEL_INDICATOR_ALL); - return true; - } - - bool CFrontPanel::powerOnAllLed() - { - powerOnLed(FRONT_PANEL_INDICATOR_ALL); - return true; - } - - bool CFrontPanel::setLED(const JsonObject& parameters) - { - stopBlinkTimer(); - bool success = false; - string ledIndicator = svc2iarm(parameters["ledIndicator"].String()); - int brightness = -1; - - if (parameters.HasLabel("brightness")) - //brightness = properties["brightness"].Number(); - getNumberParameter("brightness", brightness); - - unsigned int color = 0; - if (parameters.HasLabel("color")) //color mode 2 - { - string colorString = parameters["color"].String(); - try - { - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setColor(device::FrontPanelIndicator::Color::getInstance(colorString.c_str()), false); - success = true; - } - catch (...) - { - success = false; - } - } - else if (parameters.HasLabel("red")) //color mode 1 - { - unsigned int red = 0, green = 0, blue = 0; - - getNumberParameter("red", red); - getNumberParameter("green", green); - getNumberParameter("blue", blue); - - color = (red << 16) | (green << 8) | blue; - try - { - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setColor(color); - success = true; - } - catch (...) - { - success = false; - } - } - - LOGWARN("setLed ledIndicator: %s brightness: %d", parameters["ledIndicator"].String().c_str(), brightness); - try - { - if (brightness == -1) - brightness = device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).getBrightness(); - - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setBrightness(brightness, false); - success = true; - } - catch (...) - { - success = false; - } - return success; - } - - void CFrontPanel::setBlink(const JsonObject& blinkInfo) - { - stopBlinkTimer(); - m_blinkList.clear(); - string ledIndicator = svc2iarm(blinkInfo["ledIndicator"].String()); - int iterations = 0; - getNumberParameterObject(blinkInfo, "iterations", iterations); - JsonArray patternList = blinkInfo["pattern"].Array(); - for (int i = 0; i < patternList.Length(); i++) - { - JsonObject frontPanelBlinkHash = patternList[i].Object(); - FrontPanelBlinkInfo frontPanelBlinkInfo; - frontPanelBlinkInfo.ledIndicator = ledIndicator; - int brightness = -1; - if (frontPanelBlinkHash.HasLabel("brightness")) - getNumberParameterObject(frontPanelBlinkHash, "brightness", brightness); - - int duration = 0; - getNumberParameterObject(frontPanelBlinkHash, "duration", duration); - LOGWARN("setBlink ledIndicator: %s iterations: %d brightness: %d duration: %d", ledIndicator.c_str(), iterations, brightness, duration); - frontPanelBlinkInfo.brightness = brightness; - frontPanelBlinkInfo.durationInMs = duration; - frontPanelBlinkInfo.colorValue = 0; - if (frontPanelBlinkHash.HasLabel("color")) //color mode 2 - { - string color = frontPanelBlinkHash["color"].String(); - frontPanelBlinkInfo.colorName = color; - frontPanelBlinkInfo.colorMode = 2; - } - else if (frontPanelBlinkHash.HasLabel("red")) //color mode 1 - { - unsigned int red = 0, green = 0, blue = 0; - - getNumberParameterObject(frontPanelBlinkHash, "red", red); - getNumberParameterObject(frontPanelBlinkHash, "green", green); - getNumberParameterObject(frontPanelBlinkHash, "blue", blue); - - frontPanelBlinkInfo.colorValue = (red << 16) | (green << 8) | blue; - frontPanelBlinkInfo.colorMode = 1; - } - else - { - frontPanelBlinkInfo.colorMode = 0; - } - m_blinkList.push_back(frontPanelBlinkInfo); - } - startBlinkTimer(iterations); - } - - JsonObject CFrontPanel::getPreferences() - { - return m_preferencesHash; - } - - void CFrontPanel::setPreferences(const JsonObject& preferences) - { - m_preferencesHash = preferences; - - Core::File file; - file = FP_SETTINGS_FILE_JSON; - - file.Open(false); - if (!file.IsOpen()) - file.Create(); - - m_preferencesHash.IElement::ToFile(file); - - file.Close(); - Utils::syncPersistFile (FP_SETTINGS_FILE_JSON); - } - - void CFrontPanel::loadPreferences() - { - m_preferencesHash.Clear(); - - Core::File file; - file = FP_SETTINGS_FILE_JSON; - - file.Open(); - m_preferencesHash.IElement::FromFile(file); - - file.Close(); - } - - void CFrontPanel::startBlinkTimer(int numberOfBlinkRepeats) - { - LOGWARN("startBlinkTimer numberOfBlinkRepeats: %d m_blinkList.length : %zu", numberOfBlinkRepeats, m_blinkList.size()); - stopBlinkTimer(); - m_numberOfBlinks = 0; - m_isBlinking = true; - m_maxNumberOfBlinkRepeats = numberOfBlinkRepeats; - m_currentBlinkListIndex = 0; - if (m_blinkList.size() > 0) - { - FrontPanelBlinkInfo blinkInfo = m_blinkList.at(0); - setBlinkLed(blinkInfo); - if (m_isBlinking) - blinkTimer.Schedule(Core::Time::Now().Add(blinkInfo.durationInMs), m_blinkTimer); - } - } - - void CFrontPanel::stopBlinkTimer() - { - m_isBlinking = false; - blinkTimer.Revoke(m_blinkTimer); - } - - void CFrontPanel::setBlinkLed(FrontPanelBlinkInfo blinkInfo) - { - std::string ledIndicator = blinkInfo.ledIndicator; - int brightness = blinkInfo.brightness; - try - { - if (blinkInfo.colorMode == 1) - { - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setColor(blinkInfo.colorValue, false); - } - else if (blinkInfo.colorMode == 2) - { - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setColor(device::FrontPanelIndicator::Color::getInstance(blinkInfo.colorName.c_str()), false); - } - - } - catch (...) - {} - try - { - if (brightness == -1) - brightness = device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).getBrightness(); - - device::FrontPanelIndicator::getInstance(ledIndicator.c_str()).setBrightness(brightness, false); - } - catch (...) - { - LOGWARN("Exception caught in setBlinkLed for setBrightness "); - } - } - - void CFrontPanel::onBlinkTimer() - { - m_currentBlinkListIndex++; - bool blinkAgain = true; - if ((size_t)m_currentBlinkListIndex >= m_blinkList.size()) - { - blinkAgain = false; - m_currentBlinkListIndex = 0; - m_numberOfBlinks++; - if (m_maxNumberOfBlinkRepeats < 0 || m_numberOfBlinks <= m_maxNumberOfBlinkRepeats) - { - blinkAgain = true; - } - } - if (blinkAgain) - { - FrontPanelBlinkInfo blinkInfo = m_blinkList.at(m_currentBlinkListIndex); - setBlinkLed(blinkInfo); - if (m_isBlinking) - blinkTimer.Schedule(Core::Time::Now().Add(blinkInfo.durationInMs), m_blinkTimer); - } - - //if not blink again then the led color should stay on the LAST element in the array as stated in the spec - } - - void CFrontPanel::set24HourClock(bool is24Hour) - { - try - { - int newFormat = is24Hour ? device::FrontPanelTextDisplay::kModeClock24Hr : device::FrontPanelTextDisplay::kModeClock12Hr; - device::FrontPanelTextDisplay &textDisplay = device::FrontPanelConfig::getInstance().getTextDisplay("Text"); - int currentFormat = textDisplay.getCurrentTimeFormat(); - LOGINFO("set24HourClock - Before setting %d - Time zone read from DS is %d", newFormat, currentFormat); - textDisplay.setTimeFormat(newFormat); - currentFormat = textDisplay.getCurrentTimeFormat(); - LOGINFO("set24HourClock - After setting %d - Time zone read from DS is %d", newFormat, currentFormat); - } - catch (...) - { - LOGERR("Exception Caught during set24HourClock"); - } - } - - bool CFrontPanel::is24HourClock() - { - bool is24Hour = false; - try - { - device::FrontPanelTextDisplay &textDisplay = device::FrontPanelConfig::getInstance().getTextDisplay("Text"); - int currentFormat = textDisplay.getCurrentTimeFormat(); - LOGINFO("is24HourClock - Time zone read from DS is %d", currentFormat); - is24Hour = currentFormat == device::FrontPanelTextDisplay::kModeClock24Hr; - } - catch (...) - { - LOGERR("Exception Caught during is24HourClock"); - } - return is24Hour; - } - - uint64_t BlinkInfo::Timed(const uint64_t scheduledTime) - { - - uint64_t result = 0; - m_frontPanel->onBlinkTimer(); - return(result); - } - - } -} - -/** @} */ -/** @} */ diff --git a/helpers/frontpanel.h b/helpers/frontpanel.h deleted file mode 100644 index d9b441c..0000000 --- a/helpers/frontpanel.h +++ /dev/null @@ -1,151 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -/** -* @defgroup servicemanager -* @{ -* @defgroup include -* @{ -**/ - - -#ifndef FRONTPANEL_H -#define FRONTPANEL_H - -#include -#include -#include - -#include - -namespace WPEFramework -{ - - namespace Plugin - { - - class FrontPanel; - class CFrontPanel; - - class BlinkInfo - { - private: - BlinkInfo() = delete; - BlinkInfo& operator=(const BlinkInfo& RHS) = delete; - - public: - BlinkInfo(CFrontPanel* fp) - : m_frontPanel(fp) - { - } - BlinkInfo(const BlinkInfo& copy) - : m_frontPanel(copy.m_frontPanel) - { - } - ~BlinkInfo() {} - - inline bool operator==(const BlinkInfo& RHS) const - { - return(m_frontPanel == RHS.m_frontPanel); - } - - public: - uint64_t Timed(const uint64_t scheduledTime); - - private: - CFrontPanel* m_frontPanel; - }; - - - typedef struct _FrontPanelBlinkInfo - { - std::string ledIndicator; - std::string colorName; - unsigned int colorValue; - int brightness; - int durationInMs; - int colorMode; - } FrontPanelBlinkInfo; - - typedef enum _frontPanelIndicator - { - FRONT_PANEL_INDICATOR_CLOCK, - FRONT_PANEL_INDICATOR_MESSAGE, - FRONT_PANEL_INDICATOR_POWER, - FRONT_PANEL_INDICATOR_RECORD, - FRONT_PANEL_INDICATOR_REMOTE, - FRONT_PANEL_INDICATOR_RFBYPASS, - FRONT_PANEL_INDICATOR_ALL - } frontPanelIndicator; - - class CFrontPanel - { - public: - static CFrontPanel* instance(PluginHost::IShell *service = nullptr); - bool start(); - bool stop(); - std::string getLastError(); - void addEventObserver(FrontPanel* o); - void removeEventObserver(FrontPanel* o); - bool setBrightness(int fp_brighness); - int getBrightness(); -#ifdef CLOCK_BRIGHTNESS_ENABLED - bool setClockBrightness(int brightness); - int getClockBrightness(); -#endif - bool powerOffLed(frontPanelIndicator fp_indicator); - bool powerOnLed(frontPanelIndicator fp_indicator); - bool powerOffAllLed(); - bool powerOnAllLed(); - void setPowerStatus(bool powerStatus); - JsonObject getPreferences(); - void setPreferences(const JsonObject& preferences); - bool setLED(const JsonObject& blinkInfo); - void setBlink(const JsonObject& blinkInfo); - void loadPreferences(); - void stopBlinkTimer(); - void set24HourClock(bool is24Hour); - bool is24HourClock(); - - void onBlinkTimer(); - static int initDone; - - private: - CFrontPanel(); - static CFrontPanel* s_instance; - void startBlinkTimer(int numberOfBlinkRepeats); - void setBlinkLed(FrontPanelBlinkInfo blinkInfo); - JsonObject m_preferencesHash; // is this needed - - BlinkInfo m_blinkTimer; - bool m_isBlinking; - std::vector m_blinkList; - std::list observers_; - - std::string lastError_; - }; - } // namespace Plugin -} // namespace WPEFramework - - -#endif - - -/** @} */ -/** @} */ diff --git a/helpers/tptimer.h b/helpers/tptimer.h deleted file mode 100644 index 25b43ee..0000000 --- a/helpers/tptimer.h +++ /dev/null @@ -1,140 +0,0 @@ -/** -* If not stated otherwise in this file or this component's LICENSE -* file the following copyright and licenses apply: -* -* Copyright 2019 RDK Management -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -**/ - -#ifndef TTIMER_H -#define TTIMER_H - -//#include -#include - -namespace WPEFramework { - -namespace Plugin { - class TpTimer { - private: - class TpTimerJob { - private: - TpTimerJob() = delete; - TpTimerJob& operator=(const TpTimerJob& RHS) = delete; - - public: - TpTimerJob(TpTimer* tpt) - : m_tptimer(tpt) - { - } - TpTimerJob(const TpTimerJob& copy) - : m_tptimer(copy.m_tptimer) - { - } - ~TpTimerJob() {} - - inline bool operator==(const TpTimerJob& RHS) const - { - return (m_tptimer == RHS.m_tptimer); - } - - public: - uint64_t Timed(const uint64_t scheduledTime) - { - if (m_tptimer) { - m_tptimer->Timed(); - } - return 0; - } - - private: - TpTimer* m_tptimer; - }; - - public: - TpTimer() - : baseTimer(64 * 1024, "ThunderPluginBaseTimer") - , m_timerJob(this) - , m_isActive(false) - , m_isSingleShot(false) - , m_intervalInMs(-1) - { - } - ~TpTimer() - { - stop(); - } - - bool isActive() - { - return m_isActive; - } - void stop() - { - baseTimer.Revoke(m_timerJob); - m_isActive = false; - } - void start() - { - baseTimer.Revoke(m_timerJob); - baseTimer.Schedule(Core::Time::Now().Add(m_intervalInMs), m_timerJob); - m_isActive = true; - } - void start(int msec) - { - setInterval(msec); - start(); - } - void setSingleShot(bool val) - { - m_isSingleShot = val; - } - void setInterval(int msec) - { - m_intervalInMs = msec; - } - - void connect(std::function callback) - { - onTimeoutCallback = callback; - } - - private: - void Timed() - { - if (onTimeoutCallback != nullptr) { - onTimeoutCallback(); - } - - if (m_isActive) { - if (m_isSingleShot) { - stop(); - } else { - start(); - } - } - } - - WPEFramework::Core::TimerType baseTimer; - TpTimerJob m_timerJob; - bool m_isActive; - bool m_isSingleShot; - int m_intervalInMs; - - std::function onTimeoutCallback; - }; -} -} - -#endif diff --git a/UserSettings/CHANGELOG.md b/plugin/CHANGELOG.md similarity index 100% rename from UserSettings/CHANGELOG.md rename to plugin/CHANGELOG.md diff --git a/UserSettings/CMakeLists.txt b/plugin/CMakeLists.txt similarity index 100% rename from UserSettings/CMakeLists.txt rename to plugin/CMakeLists.txt diff --git a/AppGateway/Module.cpp b/plugin/Module.cpp similarity index 100% rename from AppGateway/Module.cpp rename to plugin/Module.cpp diff --git a/UserSettings/Module.h b/plugin/Module.h similarity index 100% rename from UserSettings/Module.h rename to plugin/Module.h diff --git a/UserSettings/UserSettings.conf.in b/plugin/UserSettings.conf.in similarity index 100% rename from UserSettings/UserSettings.conf.in rename to plugin/UserSettings.conf.in diff --git a/UserSettings/UserSettings.config b/plugin/UserSettings.config similarity index 100% rename from UserSettings/UserSettings.config rename to plugin/UserSettings.config diff --git a/UserSettings/UserSettings.cpp b/plugin/UserSettings.cpp similarity index 100% rename from UserSettings/UserSettings.cpp rename to plugin/UserSettings.cpp diff --git a/UserSettings/UserSettings.h b/plugin/UserSettings.h similarity index 100% rename from UserSettings/UserSettings.h rename to plugin/UserSettings.h diff --git a/UserSettings/UserSettingsImplementation.cpp b/plugin/UserSettingsImplementation.cpp similarity index 100% rename from UserSettings/UserSettingsImplementation.cpp rename to plugin/UserSettingsImplementation.cpp diff --git a/UserSettings/UserSettingsImplementation.h b/plugin/UserSettingsImplementation.h similarity index 100% rename from UserSettings/UserSettingsImplementation.h rename to plugin/UserSettingsImplementation.h diff --git a/services.cmake b/services.cmake index 660c989..6cb8542 100644 --- a/services.cmake +++ b/services.cmake @@ -37,15 +37,7 @@ add_definitions(-DRDK_LOG_MILESTONE) add_definitions (-DUSE_DS) -option(PLUGIN_WAREHOUSE "PLUGIN_WAREHOUSE" ON) -option(HAS_API_HDMI_INPUT "HAS_API_HDMI_INPUT" ON) -option(PLUGIN_COPILOT "PLUGIN_COPILOT" OFF) -option(PLUGIN_FRAMERATE "PLUGIN_FRAMERATE" ON) -option(PLUGIN_STORAGE_MANAGER "PLUGIN_STORAGE_MANAGER" OFF) -option(PLUGIN_DEVICEDIAGNOSTICS "PLUGIN_DEVICEDIAGNOSTICS" ON) -option(PLUGIN_SOUNDPLAYER "PLUGIN_SOUNDPLAYER" OFF) option(PLUGIN_TELEMETRY "PLUGIN_TELEMETRY" ON) -option(PLUGIN_LEDCONTROL "PLUGIN_LEDCONTROL" ON) option(PLUGIN_CONTINUEWATCHING "PLUGIN_CONTINUEWATCHING" ON)